Пример #1
0
/**
 * z_dispatch_connection:
 * @chain this
 * @conn The new connection to dispatch
 *
 * Iterates through the chain and dispatches the connection to the
 * chain items by passing it to their callbacks (for example to
 * z_py_zorp_dispatch_accept, which passes it to Dispatcher.accepted).
 */
static void 
z_dispatch_connection(ZDispatchChain *chain, ZConnection *conn)
{
  GList *p;
  ZDispatchEntry *entry;
  gchar buf[256];
  
  z_enter();
  z_dispatch_chain_lock(chain);
  /* the list is ordered by priority */
  for (p = chain->elements; p; p = g_list_next(p))
    {
      entry = (ZDispatchEntry *) p->data;
      /*LOG
        This message reports that a new connections is coming.
       */
      z_log(entry->session_id, CORE_DEBUG, 6, "Incoming connection; %s", conn ? z_connection_format(conn, buf, sizeof(buf)) : "conn=NULL");
      if ((entry->callback)(conn, entry->callback_data))
        {
          z_dispatch_chain_unlock(chain);
          z_return();
        }
    }
  z_dispatch_chain_unlock(chain);
  
  /* nobody needed this connection, destroy it */
  /*LOG
    This message indicates that a new connection was accepted, but no
    Listenet/Receiver/Proxy was interested in it.
   */
  z_log(NULL, CORE_ERROR, 3, "Nobody was interested in this connection; %s", z_connection_format(conn, buf, sizeof(buf)));
  z_connection_destroy(conn, TRUE);
  z_return();
}
Пример #2
0
/**
 * z_policy_load:
 * @self: this
 *
 * Load and run a policy file. If the file doesn't exist or a parse error
 * happens, produces an error message in the log.
 *
 * Returns:
 * TRUE on success
 */
gboolean
z_policy_load(ZPolicy *self)
{
  FILE *script;
  int res = -1;
  
  script = fopen(self->policy_filename, "r");
  if (script)
    {
      z_policy_thread_acquire(self->main_thread);
      res = PyRun_SimpleFile(script, self->policy_filename);
      fclose(script);
      z_policy_thread_release(self->main_thread);
    }
  else
    {
      /*LOG
	This message indicates that Zorp was unable to open the policy file.
	Check the permissions of your policy file.
       */
      z_log(NULL, CORE_ERROR, 0, "Error opening policy file; filename='%s'", self->policy_filename);
    }
  
  if (res == -1)
    {
      /*LOG
	This message indicates that Zorp was unable to parse the policy file.
	Check the logs for further information on where the error occurred in the policy.
       */
      z_log(NULL, CORE_ERROR, 0, "Error parsing policy file; filename='%s'", self->policy_filename);
      /* let the error message out */
    }

  return res != -1;
}
Пример #3
0
/**
 * Decrease reference count of a blob system; destroy it if the count reaches zero.
 *
 * @param[in] self the blob system object
 *
 * This function decreases the reference count of the blob system
 * object given. If the reference count reaches zero, the blob system
 * will be destroyed. If there were pending requests in a to-be-destroyed
 * blob system, this fact will be logged.
 **/
void
z_blob_system_unref(ZBlobSystem *self)
{
  ZBlob *blob;
  GList *cur, *next;
  gint n;

  z_enter();
  g_assert(self); 
  if (z_refcount_dec(&self->ref_cnt))
    {
      self->active = FALSE;
      /** @todo FIXME: itt lockolni kell */
      g_async_queue_push(self->req_queue, Z_BLOB_THREAD_KILL);
      g_thread_join(self->thr_management);

      n = 0;
      for (cur = self->waiting_list; cur; cur = next)
        {
          next = cur->next;
          blob = (ZBlob*) cur->data;
          blob->approved = FALSE;
          z_blob_signal_ready(blob);
          self->waiting_list = g_list_delete_link(self->waiting_list, cur);
          n++;
        }
      if (n)
        z_log(NULL, CORE_INFO, 5, "Pending requests found for a to-be-destroyed blob system; num_requests='%d'", n);

      n = 0;
      for (cur = self->blobs; cur; cur = next)
        {
          next = cur->next;
          blob = (ZBlob*)cur->data;
          z_blob_unref(blob);
          n++;
        }
      if (n)
        z_log(NULL, CORE_INFO, 5, "Active blobs found in a to-be-destroyed blob system; num_blobs='%d'", n);

      if (self->dir)
        g_free(self->dir);
      if (g_mutex_trylock(self->mtx_blobsys))
        {
          g_mutex_unlock(self->mtx_blobsys);
          g_mutex_free(self->mtx_blobsys);
        }
      else
        {
          /* Some blob operations are in progress: z_blob_new, _unref, _alloc, _get_file */
        }
      g_cond_free(self->cond_thread_started);
      g_async_queue_unref(self->req_queue);
      g_list_free(self->waiting_list);
      g_free(self);
    }
  z_return();
}
Пример #4
0
/**
 * Write some data into the given position of the blob, expanding it if necessary.
 *
 * @param[in] self this
 * @param[in] pos position to write to
 * @param[in] data data to write
 * @param[in] req_datalen length of data
 * @param[in] timeout timeout
 *
 * @returns The amount of data written.
 **/
gsize
z_blob_add_copy(ZBlob *self, gint64 pos, const gchar* data, gsize req_datalen, gint timeout)
{
  off_t         err;
  gssize        written = 0;

  z_enter();
  g_assert(self);
  g_assert(data);
  g_assert(pos >= 0);
  if (z_blob_lock(self, timeout))
    {
      if (self->alloc_size < (pos + (gssize) req_datalen))
        z_blob_alloc(self, pos + req_datalen);

      if (self->is_in_file)
        {
          gssize remain;
          err = lseek(self->fd, pos, SEEK_SET);
          
          if (err < 0)
            {
              z_log(NULL, CORE_ERROR, 0, "Blob error, lseek() failed; file='%s', error='%s'", self->filename, g_strerror(errno));
              g_assert(0);
            }
          remain = req_datalen;
          while (remain > 0)
            {
              written = write(self->fd, data, remain);
              if (written < 0)
                {
                  if (errno == EINTR)
                    {
                      continue;
                    }
                  else
                    {
                      z_log(NULL, CORE_ERROR, 0, "Blob error, write() failed; file='%s', error='%s'", self->filename, g_strerror(errno));
                      g_assert(0);
                    }
                }
              remain -= written;
            }
        }
      else
        {
          memmove(self->data + pos, data, req_datalen);
          written = req_datalen;
        }
      if (self->size < (pos + written))
        self->size = pos + written;
      self->stat.req_wr++;
      self->stat.total_wr += written;
      self->stat.last_accessed = time(NULL);
      z_blob_unlock(self);
    }
  z_return(written);
}
Пример #5
0
/**
 * Reads some data from the blob into a buffer.
 *
 * @param[in] self this
 * @param[in] pos position to read from
 * @param[in] data buffer to read into
 * @param[in] req_datalen bytes to read
 * @param[in] timeout timeout
 *
 * @returns The amount of data actually read.
 **/
gsize
z_blob_get_copy(ZBlob *self, gint64 pos, gchar* data, gsize req_datalen, gint timeout)
{
  off_t         err;
  gssize        rd = 0;

  z_enter();
  g_assert(self);
  g_assert(data);
  g_assert(pos >= 0);
  if (pos < self->size)
    {
      if (req_datalen > (guint64) (self->size - pos))
        req_datalen = self->size - pos;
      if (z_blob_lock(self, timeout))
        {
          if (self->is_in_file)
            {
              gssize remain;
              err = lseek(self->fd, pos, SEEK_SET);
              if (err < 0)
                {
                  z_log(NULL, CORE_ERROR, 0, "Blob error, lseek() failed; file='%s', error='%s'", self->filename, g_strerror(errno));
                  g_assert(0);
                }
              remain = req_datalen;
              while (remain > 0)
                {
                  rd = read(self->fd, data, remain);
                  if (rd < 0)
                    {
                      if (errno == EINTR)
                        {
                          continue;
                        }
                      else
                        {
                          z_log(NULL, CORE_ERROR, 0, "Blob error, read() failed; file='%s', error='%s'", self->filename, g_strerror(errno));
                          g_assert(0);
                        }
                    }
                  remain -= rd;
                }
            }
          else
            {
              memmove(data, self->data + pos, req_datalen);
              rd = req_datalen;
            }
          self->stat.req_rd++;
          self->stat.total_rd += rd;
          self->stat.last_accessed = time(NULL);
          z_blob_unlock(self);
        }
    }
  z_return(rd);          
}
Пример #6
0
/**
 * This function enables or disables the non-blocking mode of operation on
 * the given fd.
 *
 * @param[in] fd file descriptor to change
 * @param[in] enable specifies whether to enable or disable O_NONBLOCK
 *
 * @returns whether the operation was successful
 **/
gboolean 
z_fd_set_nonblock(int fd, gboolean enable)
{
#ifdef G_OS_WIN32

  /* Note: this assumes the fd is a socket. */
  unsigned long argp;
  argp = enable;

  if (!enable)
    {
      if (WSAEventSelect(fd, (WSAEVENT) NULL, 0) == SOCKET_ERROR)
        {
          z_log(NULL, CORE_ERROR, 3, "Disabling socket events failed; fd='%d', error='%08x'",
                fd, z_errno_get());
          return FALSE;
        }
    }

  if (ioctlsocket(fd, FIONBIO, &argp) == SOCKET_ERROR)
    {
      /*LOG
        This message indicates that changing the blocking state on the given fd
        failed for the given reason. Please report this event to the
        Zorp QA team.
       */
      z_log(NULL, CORE_ERROR, 3, "Changing blocking mode failed; fd='%d', enable='%d', error='%08x'",
            fd, enable, z_errno_get());
      return FALSE;
    }
#else
  int flags;

  if ((flags = fcntl(fd, F_GETFL)) == -1)
    return FALSE;

  if (enable)
    flags |= O_NONBLOCK;
  else
    flags &= ~O_NONBLOCK;
    
  if (fcntl(fd, F_SETFL, flags) < 0)
    {
      /*LOG
        This message indicates that changing the blocking state on the given fd
        failed for the given reason. Please report this event to the
        Zorp QA team.
       */
      z_log(NULL, CORE_ERROR, 3, "Changing blocking mode failed; fd='%d', enable='%d', error='%s'", fd, enable, g_strerror(errno));
      return FALSE;
    }
#endif

  return TRUE;
}
Пример #7
0
/**
 * Get the (absolute) filename assigned to the blob.
 *
 * @param[in] self this
 * @param[in] user Owner of the created file or NULL
 * @param[in] group Group of the created file or NULL
 * @param[in] mode Mode of the created file of -1
 * @param[in] timeout timeout
 *
 * @returns The filename
 **/
const gchar * 
z_blob_get_file(ZBlob *self, const gchar *user, const gchar *group, gint mode, gint timeout)
{
  const gchar   *res = NULL;

  z_enter();
  g_assert(self);
  if (!self->filename || !self->system)
    z_return(NULL);

  if (z_blob_lock(self, timeout))
    {
      if (!self->is_in_file)
        {
          if (self->storage_locked)
            goto exit;

          g_mutex_lock(self->system->mtx_blobsys); /* swap_out() accesses the blob systems data
                                                      directly, so it needs to be locked */
          z_blob_swap_out(self);
          g_mutex_unlock(self->system->mtx_blobsys);
        }
      if (group || user)
        {
          uid_t user_id = -1;
          gid_t group_id = -1;
          
          if (user && !z_resolve_user(user, &user_id))
            {
              z_log(NULL, CORE_ERROR, 3, "Cannot resolve user; user='******'", user);
              goto exit;
            }
          
          if (group && !z_resolve_group(group, &group_id))
            {
              z_log(NULL, CORE_ERROR, 3, "Cannot resolve group; group='%s'", group);
              goto exit;
            }
          
          if (chown(self->filename, user_id, group_id) == -1)
            goto exit;
        }

      if ((mode != -1) && (chmod(self->filename, mode) == -1))
        goto exit;

      res = self->filename;

exit:
      if (res == NULL)
        z_blob_unlock(self);
    }

  z_return(res); 
}
Пример #8
0
/**
 * binary -> base64 conversion
 *
 * @param[in] s this
 * @param[in] from_ source buffer
 * @param[in] fromlen source buffer length
 *
 * @returns Whether conversion succeeded
 **/
static gboolean
z_code_base64_encode_transform(ZCode *s, const void *from_, gsize fromlen)
{
  ZCodeBase64Encode *self = (ZCodeBase64Encode *) s;
  gsize pos, buf_used_orig;
  const guchar *from = from_;
  
  z_enter();
  z_code_grow((ZCode*)self, z_code_calculate_growing(self->super.buf_used, fromlen, self->linelen));
  
  /* This may allocate 4 excess bytes - but requires no further realloc()s.
   * Since the calculation uses buf_used, these 4 bytes won't accumulate, but
   * will be used in the future write()s, so the extra 4 is a grand total. */
 
  z_log(NULL, CORE_DUMP, 8, "Encoding base64 data; len='%" G_GSIZE_FORMAT"', phase='%d', used='%" G_GSIZE_FORMAT "', partial='0x%02x'",
        fromlen, self->phase, self->super.buf_used, self->super.buf[self->super.buf_used]);
  z_log_data_dump(NULL, CORE_DEBUG, 8, from, fromlen);

  buf_used_orig = self->super.buf_used;

  for (pos = 0; pos < fromlen; pos++)
    {
      switch (self->phase)
        {
        case 0: /* no previous partial content, (00.. ...., 00.. ....) -> (00xx xxxx, 00xx ....) */
          self->super.buf[self->super.buf_used] = from[pos] >> 2;
          z_code_base64_encode_fix(self, FALSE);
          self->super.buf[self->super.buf_used] = (from[pos] & 0x03) << 4;
          break;

        case 1: /* 2 upper bits already set, (00yy ...., 00.. ....) -> (00yy xxxx, 00xx xx..) */
          self->super.buf[self->super.buf_used] |= from[pos] >> 4;
          z_code_base64_encode_fix(self, FALSE);
          self->super.buf[self->super.buf_used] = (from[pos] & 0x0f) << 2;
          break;

        case 2: /* 4 upper bits already set, (00yy yy.., 00.. ....) -> (00yy yyxx, 00xx xxxx) */
          self->super.buf[self->super.buf_used] |= from[pos] >> 6;
          z_code_base64_encode_fix(self, FALSE);
          self->super.buf[self->super.buf_used] = from[pos] & 0x3f;
          z_code_base64_encode_fix(self, FALSE);
          break;
        }
      self->phase = (self->phase + 1) % 3;
    }
  z_log(NULL, CORE_DUMP, 8, "Encoded base64 data; len='%" G_GSIZE_FORMAT "', phase='%d', used='%" G_GSIZE_FORMAT "', partial='0x%02x'",
        self->super.buf_used - buf_used_orig, self->phase, self->super.buf_used, self->super.buf[self->super.buf_used]);
  z_log_data_dump(NULL, CORE_DEBUG, 8, self->super.buf + buf_used_orig, self->super.buf_used - buf_used_orig);

  z_leave();
  return TRUE;
}
Пример #9
0
/**
 * z_policy_call_object:
 * @func: Python method to call
 * @args: Arguments to pass to @func
 * @session_id: Session ID for logging
 *
 * Calls @func with @args, and if an error happened, sends log messages
 * (containing @session_id) to the log.
 *
 * Returns:
 * The return value of @func
 */
PyObject *
z_policy_call_object(PyObject *func, PyObject *args, gchar *session_id)
{
  PyObject *res;
  
  PyErr_Clear();
  res = PyObject_CallObject(func, args);
  
  Py_XDECREF(args);
  
  if (!res)
    {
      PyObject *m = PyImport_AddModule("sys");
      PyObject *exc, *value, *tb, *what_str;
      PyErr_Fetch(&exc, &value, &tb);
      what_str = PyString_FromString("what");

      if (PyObject_HasAttr(value, what_str))
        {
          PyObject *what = PyObject_GetAttr(value, what_str);
          PyObject *detail_str = PyString_FromString("detail");
          if (PyObject_HasAttr(value, detail_str))
            {
              PyObject *detail = PyObject_GetAttr(value, detail_str);
              z_log(session_id, CORE_ERROR, 3, "%s; reason='%s'", PyString_AsString(what), PyString_AsString(detail));
              Py_XDECREF(detail);
            }
          else
            {
              z_log(session_id, CORE_ERROR, 3, "%s;", PyString_AsString(what));
            }
          Py_XDECREF(what);
          Py_XDECREF(detail_str);
          Py_XDECREF(exc);
          Py_XDECREF(value);
          Py_XDECREF(tb);
        }
      else
        {
          PyErr_Restore(exc, value, tb);
          PyErr_Print();
        }

      Py_XDECREF(what_str);

      PyObject_SetAttrString(m, "last_traceback", Py_None);
    }

  return res;
}
Пример #10
0
/**
 * General function to allocate and initialize a ZSockAddr structure,
 * and convert a libc style sockaddr * pointer to our representation.
 *
 * @param[in] sa libc sockaddr * pointer to convert
 * @param[in] salen size of sa
 *
 * @returns new ZSockAddr instance
 **/
ZSockAddr *
z_sockaddr_new(struct sockaddr *sa, gsize salen)
{
  z_enter();
  switch (sa->sa_family)
    {
#ifndef G_OS_WIN32
    case AF_INET6:
      if (salen >= sizeof(struct sockaddr_in6))
        z_return(z_sockaddr_inet6_new2((struct sockaddr_in6 *) sa));
      break;
      
#endif
    case AF_INET:
      if (salen == sizeof(struct sockaddr_in))
        z_return(z_sockaddr_inet_new2((struct sockaddr_in *) sa));
      break;
      
#ifndef G_OS_WIN32
    case AF_UNIX:
      /* NOTE: the sockaddr_un structure might be less than struct sockaddr_un */
      z_return(z_sockaddr_unix_new2((struct sockaddr_un *) sa, salen));
#endif
    default:
      /*LOG
        This message indicates an internal error, the program tried to use an
        unsupported address family. Please report this error to the Zorp QA team.
       */
      z_log(NULL, CORE_ERROR, 3, "Unsupported socket family in z_sockaddr_new(); family='%d'", sa->sa_family);
      z_return(NULL);
    }
  z_return(NULL);
}
Пример #11
0
static void
call_data_received(TelnetProtocol *self)
{
    if (!telnet_protocol_is_running(self))
        return;

    if (z_pktbuf_length(self->data_buffer) == 0)
        return;

    z_pktbuf_seek(self->data_buffer, G_SEEK_SET, 0);

    if (self->data_received)
    {
        gboolean res = self->data_received(self->data_buffer, self->data_received_user_data);

        if (!res)
        {
            z_log(self->session_id, TELNET_DEBUG, 5, "Data received callback returned error, aborting;");
            change_state(self, PROTO_STATE_QUIT);
        }
    }

    z_pktbuf_resize(self->data_buffer, 0);

}
Пример #12
0
void
z_fd_get_peer_tos(gint fd, guint8 *tos)
{
  gint tmp;
  gchar buf[256];
  gboolean tos_found = FALSE;
  socklen_t buflen, len;
    
  z_enter();
  *tos = 0;
  tmp = 1;
  if (setsockopt(fd, SOL_IP, IP_RECVTOS, &tmp, sizeof(tmp)) < 0)
    {
      z_log(NULL, CORE_ERROR, 8, "Error in setsockopt(SOL_IP, IP_RECVTOS); fd='%d', error='%s'", fd, g_strerror(errno));
      z_leave();
      return;
    }

  buflen = sizeof(buf);
  if (getsockopt(fd, SOL_IP, IP_PKTOPTIONS, &buf, &buflen) >= 0)
    {
      struct msghdr msg;
      struct cmsghdr *cmsg;
      
      msg.msg_controllen = buflen;
      msg.msg_control = buf;
      for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg))
        {
          if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_TOS)
            {
              *tos = *(guchar *) CMSG_DATA(cmsg);
              tos_found = TRUE;
              break;
            }
        }
    }
  if (!tos_found)
    {
      len = sizeof(*tos);
      if (getsockopt(fd, SOL_IP, IP_TOS, tos, &len) == -1)
        {
          z_log(NULL, CORE_ERROR, 2, "Error in getsockopt(SOL_IP, IP_PKTOPTIONS) || getsockopt(SOL_IP, IP_TOS); fd='%d', error='%s'", fd, g_strerror(errno));
          *tos = 0;
        }
    }
  z_leave();
}
Пример #13
0
/**
 * z_policy_call_object:
 * @func: Python method to call
 * @args: Arguments to pass to @func
 * @session_id: Session ID for logging
 *
 * Calls @func with @args, and if an error happened, sends log messages
 * (containing @session_id) to the log.
 *
 * Returns:
 * The return value of @func
 */
PyObject *
z_policy_call_object(PyObject *func, PyObject *args, gchar *session_id)
{
  PyObject *res;
  
  PyErr_Clear();
  res = PyObject_CallObject(func, args);
  
  Py_XDECREF(args);
  
  if (!res)
    {
      PyObject *m = PyImport_AddModule("sys");
      
      if (!PyString_Check(PyErr_Occurred()))
        {
          PyErr_Print();
        }
      else
        {
          PyObject *exc, *value, *tb, *str;
          
          PyErr_Fetch(&exc, &value, &tb);
          PyErr_NormalizeException(&exc, &value, &tb);
          
          str = PyObject_Str(value);
          if (!str)
            {
              /*NOLOG*/
              z_log(session_id, CORE_ERROR, 3, "%s;", PyString_AsString(exc));
            }
          else
            {
              /*NOLOG*/
              z_log(session_id, CORE_ERROR, 3, "%s; reason='%s'", PyString_AsString(exc), PyString_AsString(str));
            }
          
          Py_XDECREF(exc);
          Py_XDECREF(value);
          Py_XDECREF(tb);
          Py_XDECREF(str);
        }
      PyObject_SetAttrString(m, "last_traceback", Py_None); 
    }

  return res;
}
Пример #14
0
static inline void
change_state(TelnetProtocol *self,
             TelnetProtocolState new_state)
{
    z_log(self->session_id, TELNET_DEBUG, 6, "Protocol changing state; old='%d', new='%d'", self->state, new_state);

    self->state = new_state;
}
Пример #15
0
/**
 * Writes a blob out to disk, called only from z_blob_system_threadproc()
 *
 * @param[in] self this
 *
 * @warning Caller must hold a lock BOTH on the blob AND the blob system!
 **/
static void
z_blob_swap_out(ZBlob *self)
{
  off_t err;
  gssize written, remain;

  z_enter();
  g_assert(self);
  if (!self->storage_locked && !self->is_in_file && self->system)
    {
      err = lseek(self->fd, 0, SEEK_SET);
      if (err < 0)
        {
          z_log(NULL, CORE_ERROR, 0, "Blob error, lseek() failed; file='%s', error='%s'", self->filename, g_strerror(errno));
          g_assert(0);
        }
      remain = self->size;
      while (remain > 0)
        {
          written = write(self->fd, self->data, remain);
          if (written < 0)
            {
              if (errno == EINTR)
                {
                  continue;
                }
              else
                {
                  z_log(NULL, CORE_ERROR, 0, "Blob error, write() failed; file='%s', error='%s'", self->filename, g_strerror(errno));
                  g_assert(0);
                }
            }
          remain -= written;
        }
      self->is_in_file = 1;
      g_free(self->data);
      self->data = NULL;
      self->stat.swap_count++;
      self->stat.last_accessed = time(NULL);
      self->system->mem_used -= self->alloc_size;
      self->system->disk_used += self->alloc_size;
    }
  z_return();
}
Пример #16
0
/**
 * Allocate and initialize a Zorp thread identified by a name, and
 * using the given thread function.
 *
 * @param[in] name name to identify this thread with
 * @param[in] func thread function
 * @param[in] arg pointer to pass to thread function
 *
 * @returns TRUE to indicate success
 **/
gboolean
z_thread_new(gchar *name, GThreadFunc func, gpointer arg)
{
  ZThread *self = g_new0(ZThread, 1);
  GError *error = NULL;
  static gint thread_id = 1;
  
  self->thread_id = thread_id++;
  self->func = func;
  self->arg = arg;
  strncpy(self->name, name, sizeof(self->name) - 1);
  
  g_async_queue_lock(queue);
  if (num_threads >= max_threads)
    {
      /*LOG
        This message reports that the maximal thread limit is reached. Try to increase
	the maximal thread limit.
       */
      z_log(NULL, CORE_ERROR, 3, "Too many running threads, waiting for one to become free; num_threads='%d', max_threads='%d'", num_threads, max_threads);
      g_async_queue_push_unlocked(queue, self);
      g_async_queue_unlock(queue);
    }
  else
    {
      num_threads++;
      g_async_queue_ref_unlocked(queue);
      g_async_queue_unlock(queue);
      if (!g_thread_create_full(z_thread_func, self, max_stack_size, FALSE, TRUE, G_THREAD_PRIORITY_NORMAL, &error))
        {
	  /*LOG
	    This message indicates that creating a new thread failed. It is likely that
	    the system is running low on some resources or some limit is reached.
	   */
          z_log(NULL, CORE_ERROR, 2, "Error starting new thread; error='%s'", error->message);
          g_async_queue_lock(queue);
          num_threads--;
          g_async_queue_unlock(queue);
          return FALSE;
        }
    }
  
  return TRUE;
}
Пример #17
0
/**
 * z_dispatch_chain_thread:
 * @st this
 *
 * The thread routine of a dispatcher chain, pops new connections from the
 * accept_queue and processes them by calling z_dispatch_connection.
 * When the popped connection is the special value Z_DISPATCH_THREAD_EXIT_MAGIC,
 * exits the processing loop and finishes the thread.
 * 
 * Returns: NULL
 */
static gpointer
z_dispatch_chain_thread(gpointer st)
{
  ZDispatchChain *self = (ZDispatchChain *) st;
  ZConnection *conn;
  glong acceptq_sum;
  gint count;
  
  /* g_thread_set_priority(g_thread_self(), G_THREAD_PRIORITY_HIGH); */ 
  /*LOG
   This message reports that a new dispatcher thread is starting. This is used if threaded
   dispatching is enabled.
   @see: Dispatcher
   */
  z_log(NULL, CORE_DEBUG, 4, "Dispatch thread starting;");
  acceptq_sum = 0;
  count = 0;
  while (1)
    {
      acceptq_sum += g_async_queue_length(self->accept_queue);
      if (count % 1000 == 0)
        {
          /*LOG
	    This message reports the dispatcher average accept queue length status.
	   */
	  z_log(NULL, CORE_DEBUG, 4, "Accept queue stats; avg_length='%ld'", acceptq_sum / 1000);
          acceptq_sum = 0;
        }
      conn = g_async_queue_pop(self->accept_queue);
      if (conn == Z_DISPATCH_THREAD_EXIT_MAGIC)
        break;
      z_dispatch_connection(self, conn);
      count++;
    }
  /*LOG
    This message reports that the dispatcher thread is exiting.
    It it likely that Zorp unbinds from that address.
   */
  z_log(NULL, CORE_DEBUG, 4, "Dispatch thread exiting;");
  z_dispatch_chain_unref(self);
  return NULL;
}
Пример #18
0
/**
 * Decrease reference count of blob; destroy it if the count reaches zero.
 *
 * @param[in] self this
 **/
void
z_blob_unref(ZBlob *self)
{
  z_enter();
  if (self && z_refcount_dec(&self->ref_cnt))
    {
      g_mutex_lock(self->system->mtx_blobsys);
      self->alloc_req = -self->alloc_size;
      self->system->blobs = g_list_remove(self->system->blobs, self);
      z_blob_check_alloc(self);
      g_mutex_unlock(self->system->mtx_blobsys);

      if (self->data)
        g_free(self->data);

      if (self->fd >= 0)
        close(self->fd);

      if (self->filename)
        {
          if (unlink(self->filename))
            z_log(NULL, CORE_ERROR, 3, "Error removing blob file, unlink() failed; file='%s', error='%s'", self->filename, strerror(errno));
          g_free(self->filename);
          self->filename = NULL;
        }

      g_mutex_free(self->mtx_reply);
      g_cond_free(self->cond_reply);
      if (g_mutex_trylock(self->mtx_lock))
        {
          g_mutex_unlock(self->mtx_lock);
          g_mutex_free(self->mtx_lock);
        }
      else
        {
          z_log(NULL, CORE_ERROR, 3, "Error while destroying blob, someone still has a lock on it;");
          /* someone has locked the blob by z_blob_get_file or _get_ptr, and forgot to release it */
        }
      g_free(self);
    }
  z_return();
}
Пример #19
0
void
z_fd_get_our_tos(gint fd, guint8 *tos)
{
  socklen_t len;
  
  *tos = 0;
  len = sizeof(*tos);
  if (getsockopt(fd, SOL_IP, IP_TOS, tos, &len) < 0)
    {
      z_log(NULL, CORE_ERROR, 2, "Error in getsockopt(SOL_IP, IP_TOS); fd='%d', error='%s'", fd, g_strerror(errno));
    }
}
Пример #20
0
/**
 * This function is called upon thread startup and performs thread specific
 * initialization. It calls thread-start and thread-exit callbacks.
 *
 * @param[in] self thread specific variables
 * @param     user_data pointer to pass to real thread function (unused)
 **/
static void
z_thread_func_core(ZThread *self, gpointer user_data G_GNUC_UNUSED)
{
  g_private_set(current_thread, self);
  self->thread = g_thread_self();

  z_thread_iterate_callbacks(self, start_callbacks);

  /*LOG
    This message indicates that a thread is starting.
  */
  z_log(self->name, CORE_DEBUG, 6, "thread starting;");
  (*self->func)(self->arg);
  /*LOG
    This message indicates that a thread is ending.
  */
  z_log(self->name, CORE_DEBUG, 6, "thread exiting;");

  z_thread_iterate_callbacks(self, stop_callbacks);  
  z_thread_free(self);

}
Пример #21
0
void
z_fd_set_our_tos(gint fd, guint8 tos)
{
  socklen_t len;
  cap_t saved_caps;
  
  saved_caps = cap_save();
  len = sizeof(tos);
  cap_enable(CAP_NET_ADMIN);
  if (setsockopt(fd, SOL_IP, IP_TOS, &tos, len) < 0)
    {
      if (errno != ENOTSOCK && errno != EOPNOTSUPP)
        {
          z_log(NULL, CORE_ERROR, 3, "Error setting ToS value on socket; fd='%d', tos='%d', error='%s', errno='%d'", fd, tos, g_strerror(errno), errno);
        }
    }
  else
    {
      z_log(NULL, CORE_DEBUG, 6, "Setting socket ToS value; fd='%d', tos='%d'", fd, tos);
    }
  cap_restore(saved_caps);
}
Пример #22
0
/**
 * Release the lock on the blob after z_blob_get_file.
 *
 * @param[in] self this
 *
 * Besides releasing the lock itself, this function also updates the
 * blob size from the file size.
 **/
void
z_blob_release_file(ZBlob *self)
{
  struct stat st;
  
  z_enter();
  g_assert(self);
  if (!fstat(self->fd, &st))
    self->size = self->alloc_size = st.st_size;
  else
    z_log(NULL, CORE_ERROR, 3, "Cannot stat file on release, blob size may be incorrect from now;");
  z_blob_unlock(self);
  z_return();
}
Пример #23
0
gboolean
z_kzorp_get_lookup_result(gint fd, struct z_kzorp_lookup_result *result)
{
  socklen_t size = sizeof(*result);

  z_enter();

  if (getsockopt(fd, SOL_IP, SO_KZORP_RESULT, result, &size) < 0)
    {
      z_log(NULL, CORE_ERROR, 3, "Error querying KZorp lookup result; fd='%d', error='%s'", fd, g_strerror(errno));
      z_return(FALSE);
    }

  z_return(TRUE);
}
Пример #24
0
/**
 * This function enables or disables the TCP SO_OOBINLINE feature for socket
 * specified by fd.
 *
 * @param[in] fd file descriptor of a socket
 * @param[in] enable whether to enable or disable TCP SO_OOBINLINE
 *
 * @returns whether the operation was successful
 **/
gboolean
z_fd_set_oobinline(int fd, gboolean enable)
{
  if (setsockopt(fd, SOL_SOCKET, SO_OOBINLINE, (char *)(&enable), sizeof(enable)) == -1)
    {
      /*LOG
        This message indicates that changing the OOBINLINE state on the given fd
        failed for the given reason. Please report this event to the 
        Zorp QA team.
       */
      z_log(NULL, CORE_ERROR, 4, "setsockopt(SOL_SOCKET, SO_OOBINLINE) failed; fd='%d', enable='%d', error='%s'", fd, enable, g_strerror(errno));
      return FALSE;
    }
  return TRUE;
}
Пример #25
0
/**
 * Create a new blob.
 *
 * @param[in] sys Blob system to create the blob into
 * @param[in] initial_size Initial size to allocate.
 *
 * This function creates a new blob. If sys is NULL, z_blob_system_default will be used.
 *
 * @returns The new blob instance
 **/
ZBlob*
z_blob_new(ZBlobSystem *sys, gsize initial_size)
{
  ZBlob   *self;

  z_enter();
  if (!sys)
    sys = z_blob_system_default;

  if (!sys || !sys->active) 
    z_return(NULL);

  self = g_new0(ZBlob, 1);
  self->system = sys;

  self->filename = g_strdup_printf("%s/blob_XXXXXX", self->system->dir);
  self->fd = mkstemp(self->filename);

  if (self->fd < 0)
    {
      z_log(NULL, CORE_ERROR, 2, "Error creating blob file: file='%s', error='%s'", self->filename, strerror(errno));
      g_free(self->filename);
      g_free(self);
      z_return(NULL);
    }
  
  z_refcount_set(&self->ref_cnt, 1);
  self->size = 0;
  self->alloc_size = 0;
  self->data = NULL;
  self->is_in_file = FALSE;
  self->mtx_reply = g_mutex_new();
  self->cond_reply = g_cond_new();
  self->mapped_ptr = NULL;
  self->mapped_length = 0;
  self->storage_locked = FALSE;

  z_blob_statistic_init(&self->stat);
  self->mtx_lock = g_mutex_new();

  g_mutex_lock(self->system->mtx_blobsys);
  self->system->blobs = g_list_append(self->system->blobs, self);
  g_mutex_unlock(self->system->mtx_blobsys);

  if (initial_size > 0)
    z_blob_alloc(self, initial_size);
  z_return(self);
}
Пример #26
0
static void
call_command_received(TelnetProtocol *self)
{
    if (!telnet_protocol_is_running(self))
        return;

    if (self->command_received)
    {
        gboolean res = self->command_received(self->command, self->command_received_user_data);

        if (!res)
        {
            z_log(self->session_id, TELNET_DEBUG, 5, "Command callback returned error, aborting;");
            change_state(self, PROTO_STATE_QUIT);
        }
    }
}
Пример #27
0
/**
 * z_policy_stream_new:
 * @str: ZStream instance
 *
 * This function allocates a Python object representing the Zorp stream
 * @str. It is to be called from C code, the Python version of this
 * constructor is below.
 * 
 * Returns: the newly allocated Python object
 **/
PyObject *
z_policy_stream_new(ZStream *str)
{
  ZPolicyStream *self;

  if (str == NULL)
    {
      /*LOG
        This message indicates an internal error, please contact your Zorp support for assistance.
       */
      z_log(NULL, CORE_ERROR, 3, "Internal error in z_policy_stream_new: input ZStream is NULL;");
      return NULL;
    }

  self = PyObject_New(ZPolicyStream, &z_policy_stream_type);
  z_stream_ref(str);
  self->stream = str;
  return (PyObject *) self;
}
Пример #28
0
void
z_fatal_signal_handler(int signo)
{
  ZSignalContext *p = z_stackdump_get_context(p);
  struct sigaction act;

  memset(&act, 0, sizeof(act));
  act.sa_handler = SIG_DFL;
  sigaction(signo, &act, NULL);

  /*LOG
    This message is logged when Zorp caught a fatal signal.
    Possible reason is bad RAM or other hardware.
   */
  z_log(NULL, CORE_ERROR, 0, "Signal received, stackdump follows; signo='%d'", signo);
  z_mem_trace_stats();
  z_stackdump_log(p);
  kill(getpid(), signo);
}
Пример #29
0
static inline void
append_byte(TelnetProtocol *self, ZPktBuf *buf, guint8 byte)
{
    /* stop on buffer overrun */
    if (z_pktbuf_length(buf) >= TELNET_BUFFER_SIZE)
    {
        /*LOG
          This message indicates that the Telnet protocol contained a sequence of
          protocol elements that would have needed an unreasonably large buffer to
          process. These structures are not commonly found in normal Telnet
          streams but could be used to mount a denial of service attack on a
          Telnet client or server by a malicious host.
         */
        z_log(self->session_id, TELNET_VIOLATION, 1, "Buffer overflow during protocol decoding, aborting session; buffer_length='%" G_GSIZE_FORMAT "'",
              z_pktbuf_length(buf));
        change_state(self, PROTO_STATE_QUIT);
    }
    else
        z_pktbuf_put_u8(buf, byte);
}
Пример #30
0
/**
 * Finalize Base64 decoding.
 *
 * @param[in] s ZCodeBase64Decode instance
 *
 * Checks if the input was complete (if so, we returned to phase 0).
 * If it wasn't, the error is logged; and if we're not error_tolerant,
 * the return value also indicates this error condition.
 *
 * @return always TRUE if error_tolerant; otherwise FALSE if the input was incomplete
 **/
static gboolean
z_code_base64_decode_finish(ZCode *s)
{
  ZCodeBase64Decode *self = (ZCodeBase64Decode *) s;
  
  z_enter();
  if (self->phase != 0)
    {
      z_log(NULL, CORE_ERROR, 3, "Unfinished base64 encoding; phase='%d'", self->phase);
      self->phase = 0;
      if (!self->error_tolerant)
        {
          z_leave();
          return FALSE;
        }
    }

  z_leave();
  return TRUE;
}