[gnome-nibbles/gnome-3-10] Copy scores-backend.c and setgid-io.c from glines



commit 126f83d67414cc4e3b3e4c013fdb94b37de8cc84
Author: Michael Catanzaro <mcatanzaro gnome org>
Date:   Tue Nov 5 22:30:16 2013 -0600

    Copy scores-backend.c and setgid-io.c from glines
    
    For some reason we were stuck with a stub instead of a real copy of
    games-scores-backend.

 src/Makefile.am            |    2 +
 src/games-scores-backend.c |  223 +++++++++++++++++-
 src/games-scores-backend.h |    4 +
 src/games-setgid-io.c      |  558 ++++++++++++++++++++++++++++++++++++++++++++
 src/games-setgid-io.h      |   38 +++
 5 files changed, 823 insertions(+), 2 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 825d1ad..6bfbcda 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -25,6 +25,8 @@ gnome_nibbles_SOURCES = \
        games-scores-dialog.h   \
        games-scores-backend.c  \
        games-scores-backend.h  \
+       games-setgid-io.c \
+       games-setgid-io.h \
        gnibbles.h \
        gnibbles.c \
        properties.h \
diff --git a/src/games-scores-backend.c b/src/games-scores-backend.c
index 6d138a9..f574713 100644
--- a/src/games-scores-backend.c
+++ b/src/games-scores-backend.c
@@ -30,7 +30,14 @@
 #include "games-scores.h"
 #include "games-scores-backend.h"
 
+#ifdef ENABLE_SETGID
+#include "games-setgid-io.h"
+#endif
+
 struct GamesScoresBackendPrivate {
+#ifdef ENABLE_SETGID
+  gboolean setgid_io_initialized;
+#endif
   GList *scores_list;
   GamesScoreStyle style;
   time_t timestamp;
@@ -43,7 +50,9 @@ G_DEFINE_TYPE (GamesScoresBackend, games_scores_backend, G_TYPE_OBJECT);
 void
 games_scores_backend_startup (void)
 {
-
+#ifdef ENABLE_SETGID
+  setgid_io_init ();
+#endif
 }
 
 static void
@@ -102,7 +111,56 @@ games_scores_backend_new (GamesScoreStyle style,
   return backend;
 }
 
+#ifdef ENABLE_SETGID
+
+/* Get a lock on the scores file. Block until it is available. 
+ * This also supplies the file descriptor we need. The return value
+ * is whether we were succesful or not. */
+static gboolean
+games_scores_backend_get_lock (GamesScoresBackend * self)
+{
+  gint error;
+
+  if (self->priv->fd != -1) {
+    /* Assume we already have the lock and rewind the file to
+     * the beginning. */
+    setgid_io_seek (self->priv->fd, 0, SEEK_SET);
+    return TRUE;                /* Assume we already have the lock. */
+  }
+
+  self->priv->fd = setgid_io_open (self->priv->filename, O_RDWR);
+  if (self->priv->fd == -1) {
+    return FALSE;
+  }
+
+  error = setgid_io_lock (self->priv->fd);
+
+  if (error == -1) {
+    setgid_io_close (self->priv->fd);
+    self->priv->fd = -1;
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+/* Release the lock on the scores file and dispose of the fd. */
+/* We ignore errors, there is nothing we can do about them. */
+static void
+games_scores_backend_release_lock (GamesScoresBackend * self)
+{
+  /* We don't have a lock, ignore this call. */
+  if (self->priv->fd == -1)
+    return;
+
+  setgid_io_unlock (self->priv->fd);
+
+  setgid_io_close (self->priv->fd);
 
+  self->priv->fd = -1;
+}
+
+#endif /* ENABLE_SETGID */
 
 /**
  * games_scores_backend_get_scores:
@@ -117,17 +175,178 @@ games_scores_backend_new (GamesScoreStyle style,
 GList *
 games_scores_backend_get_scores (GamesScoresBackend * self)
 {
+#ifdef ENABLE_SETGID
+  gchar *buffer;
+  gchar *eol;
+  gchar *scorestr;
+  gchar *timestr;
+  gchar *namestr;
+  GamesScore *newscore;
+  struct stat info;
+  int error;
+  ssize_t length, target;
+  GList *t;
+  
+  /* Check for a change in the scores file and update if necessary. */
+  error = setgid_io_stat (self->priv->filename, &info);
+
+  /* If an error occurs then we give up on the file and return NULL. */
+  if (error != 0)
+    return NULL;
+
+  if ((info.st_mtime > self->priv->timestamp) || (self->priv->scores_list == NULL)) {
+    self->priv->timestamp = info.st_mtime;
+
+    /* Dump the old list of scores. */
+    t = self->priv->scores_list;
+    while (t != NULL) {
+      g_object_unref (t->data);
+      t = g_list_next (t);
+    }
+    g_list_free (self->priv->scores_list);
+    self->priv->scores_list = NULL;
+
+    /* Lock the file and get the list. */
+    if (!games_scores_backend_get_lock (self))
+      return NULL;
+
+    buffer = g_malloc (info.st_size + 1);
+    if (buffer == NULL) {
+      games_scores_backend_release_lock (self);
+      return NULL;
+    }
+
+    target = info.st_size;
+    length = 0;
+    do {
+      target -= length;
+      length = setgid_io_read (self->priv->fd, buffer, info.st_size);
+      if (length == -1) {
+        games_scores_backend_release_lock (self);
+        g_free (buffer);
+        return NULL;
+      }
+    } while (length < target);
+
+    buffer[info.st_size] = '\0';
+
+    /* FIXME: These details should be in a sub-class. */
+
+    /* Parse the list. We start by breaking it into lines. */
+    /* Since the buffer is null-terminated 
+     * we can do the string stuff reasonably safely. */
+    eol = strchr (buffer, '\n');
+    scorestr = buffer;
+    while (eol != NULL) {
+      *eol++ = '\0';
+      timestr = strchr (scorestr, ' ');
+      if (timestr == NULL)
+        break;
+      *timestr++ = '\0';
+      namestr = strchr (timestr, ' ');
+      if (namestr == NULL)
+        break;
+      *namestr++ = '\0';
+      /* At this point we have three strings, all null terminated. All
+       * part of the original buffer. */
+      switch (self->priv->style) {
+      case GAMES_SCORES_STYLE_PLAIN_DESCENDING:
+      case GAMES_SCORES_STYLE_PLAIN_ASCENDING:
+        newscore = games_score_new_plain (g_ascii_strtod (scorestr, NULL));
+        break;
+      case GAMES_SCORES_STYLE_TIME_DESCENDING:
+      case GAMES_SCORES_STYLE_TIME_ASCENDING:
+        newscore = games_score_new_time (g_ascii_strtod (scorestr, NULL));
+        break;
+      default:
+        g_assert_not_reached ();
+      }
+      games_score_set_name (newscore, namestr);
+      games_score_set_time (newscore, g_ascii_strtoull (timestr, NULL, 10));
+      self->priv->scores_list = g_list_append (self->priv->scores_list, newscore);
+      /* Setup again for the next time around. */
+      scorestr = eol;
+      eol = strchr (eol, '\n');
+    }
+
+    g_free (buffer);
+  }
+
+  /* FIXME: Sort the scores! We shouldn't rely on the file being sorted. */
+
+  return self->priv->scores_list;
+#else
   return NULL;
+#endif /* ENABLE_SETGID */
 }
 
 gboolean
 games_scores_backend_set_scores (GamesScoresBackend * self, GList * list)
 {
+#ifdef ENABLE_SETGID
+  GList *s;
+  GamesScore *d;
+  gchar *buffer;
+  gint output_length = 0;
+  gchar dtostrbuf[G_ASCII_DTOSTR_BUF_SIZE];
+
+  if (!games_scores_backend_get_lock (self))
+    return FALSE;
+
+  self->priv->scores_list = list;
+
+  s = list;
+  while (s != NULL) {
+    gdouble rscore;
+    guint64 rtime;
+    const gchar *rname;
+
+    d = (GamesScore *) s->data;
+    rscore = 0.0;
+    switch (self->priv->style) {
+    case GAMES_SCORES_STYLE_PLAIN_DESCENDING:
+    case GAMES_SCORES_STYLE_PLAIN_ASCENDING:
+      rscore = games_score_get_value_as_plain (d);
+      break;
+    case GAMES_SCORES_STYLE_TIME_DESCENDING:
+    case GAMES_SCORES_STYLE_TIME_ASCENDING:
+      rscore = games_score_get_value_as_time(d);
+      break;
+    default:
+      g_assert_not_reached ();
+    }
+    rtime = games_score_get_time (d);
+    rname = games_score_get_name(d);
+
+    buffer = g_strdup_printf ("%s %"G_GUINT64_FORMAT" %s\n",
+                              g_ascii_dtostr (dtostrbuf, sizeof (dtostrbuf),
+                                              rscore), rtime, rname);
+    setgid_io_write (self->priv->fd, buffer, strlen (buffer));
+    output_length += strlen (buffer);
+    /* Ignore any errors and blunder on. */
+    g_free (buffer);
+
+    s = g_list_next (s);
+  }
+
+  /* Remove any content in the file that hasn't yet been overwritten. */
+  setgid_io_truncate (self->priv->fd, output_length--);
+
+  /* Update the timestamp so we don't reread the scores unnecessarily. */
+  self->priv->timestamp = time (NULL);
+
+  games_scores_backend_release_lock (self);
+
+  return TRUE;
+#else
   return FALSE;
+#endif /* ENABLE_SETGID */
 }
 
 void
 games_scores_backend_discard_scores (GamesScoresBackend * self)
 {
-
+#ifdef ENABLE_SETGID
+  games_scores_backend_release_lock (self);
+#endif
 }
diff --git a/src/games-scores-backend.h b/src/games-scores-backend.h
index c094431..131fb4b 100644
--- a/src/games-scores-backend.h
+++ b/src/games-scores-backend.h
@@ -28,6 +28,10 @@
 
 #include "games-score.h"
 
+#ifdef ENABLE_SETGID
+#include "games-setgid-io.h"
+#endif
+
 G_BEGIN_DECLS
 
 #define GAMES_TYPE_SCORES_BACKEND (games_scores_backend_get_type ())
diff --git a/src/games-setgid-io.c b/src/games-setgid-io.c
new file mode 100644
index 0000000..f175c15
--- /dev/null
+++ b/src/games-setgid-io.c
@@ -0,0 +1,558 @@
+/* games-setgid-io.c : Routines to perform I/O in a seperate setgid
+ *                     subprocess.
+ *
+ * Copyright (C) 2005 by Callum McKenzie
+ *
+ * Time-stamp: <2006-02-15 18:55:54 callum>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* WARNING: The purpose of this code is to subvert GTK's checks
+ * against setuid/setgid code. It does this by running a separate
+ * process that retains setgid privileges while the main code drops
+ * its privileges and runs the main code. The two processes
+ * communicate by a pipe. This interface is very liberal - effectively
+ * providing the standard file i/o operations with the privileges of
+ * the original executable. This is bad security. The
+ * privileged/non-privileged interface should be one more layer out so
+ * that data passing through it can be checked more rigorously. It
+ * isn't this way because a different security mechanism was assumed
+ * during the design of the scoring system and this is the simplest way to 
+ * retrofit the setgid security system.
+ *
+ * In practise security shouldn't be compromised much more than it
+ * already was. The new threat is that a compromised game could
+ * over-write (or create) any file with games privileges. In the old
+ * code this was less likely since both the game code and the
+ * privileged code would have to be compromised. In any event, if
+ * games privileges are significant in your system then you have
+ * bigger security problems than this code.
+ */
+
+/* We almost directly wrap the standard open/close/read/write/seek
+ * functions and we wrap flock in a simpler lock primitive. 
+ *
+ * Each function has two forms: one half that does the actual work -
+ * suffixed with _priv - and a wrapper that is called from the
+ * insecure side which stuffs the arguments down the pipe connecting
+ * the two processes.
+ *
+ * From the point of view of the caller, these functions should behave
+ * transparently with the exception of having to call setgid_io_init
+ * () right at the beginning of the program.
+ *
+ */
+
+#include <config.h>
+
+#include <glib.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+
+#include "games-setgid-io.h"
+
+enum {
+  cmd_open = 1,
+  cmd_close,
+  cmd_read,
+  cmd_write,
+  cmd_seek,
+  cmd_lock,
+  cmd_unlock,
+  cmd_stat,
+  cmd_truncate
+} commands;
+
+/* Global state variables, the program only has one global instance of
+   this module. */
+static gboolean setgid_io_initialised = 0;
+/* These names are from the point of view of the non-setgid parent. */
+static int setgid_io_infd;
+static int setgid_io_outfd;
+static int setgid_io_child_pid;
+
+
+static void
+write_cmd (unsigned char cmd)
+{
+  int cnt;
+  cnt = write (setgid_io_outfd, &cmd, 1);
+  if (cnt != 1)  {
+    g_warning ("An error occurred while writing to file");
+  }
+}
+
+
+static gboolean
+write_n_bytes (int fd, const char *buffer, int n)
+{
+  int totalcnt;
+  int cnt;
+
+  totalcnt = 0;
+  while (totalcnt < n) {
+    cnt = write (fd, buffer + totalcnt, n);
+    if (cnt == -1)
+      return FALSE;
+    totalcnt += cnt;
+  }
+
+  return TRUE;
+}
+
+static gboolean
+read_n_bytes (int fd, char *buffer, int n)
+{
+  int totalcnt;
+  int cnt;
+
+  totalcnt = 0;
+  while (totalcnt < n) {
+    cnt = read (fd, buffer + totalcnt, n);
+    if (cnt == -1)
+      return FALSE;
+    totalcnt += cnt;
+  }
+
+  return TRUE;
+}
+
+static void
+write_int (int fd, int i)
+{
+  int cnt;
+  cnt = write (fd, &i, sizeof (int));
+  if (cnt != sizeof (int))  {
+    g_warning ("An error occurred while writing to file");
+  }
+}
+
+static int
+read_int (int fd)
+{
+  int out;
+
+  if (!read_n_bytes (fd, (char *) &out, sizeof (int)))
+    return 0;
+
+  return out;
+}
+
+static void
+write_off_t (int fd, off_t o)
+{
+  int cnt;
+  cnt = write (fd, &o, sizeof (off_t));
+  if (cnt != sizeof (off_t))  {
+    g_warning ("An error occurred while writing to file");
+  }
+}
+
+static off_t
+read_off_t (int fd)
+{
+  off_t out;
+
+  if (!read_n_bytes (fd, (char *) &out, sizeof (off_t)))
+    return 0;
+
+  return out;
+}
+
+/* Unprivileged side. */
+int
+setgid_io_open (const char *path, int flags)
+{
+  int length;
+  int fd;
+
+  write_cmd (cmd_open);
+
+  length = strlen (path) + 1;
+  write_int (setgid_io_outfd, length);
+  write_n_bytes (setgid_io_outfd, path, length);
+  write_int (setgid_io_outfd, flags);
+
+  fd = read_int (setgid_io_infd);
+
+  return fd;
+}
+
+/* Privileged side. */
+static void
+setgid_io_open_priv (int outfd, int infd)
+{
+  int length;
+  char *path;
+  int flags;
+  int newfd;
+
+  length = read_int (infd);
+  path = g_malloc (length);
+  read_n_bytes (infd, path, length);
+  flags = read_int (infd);
+
+  newfd = open (path, flags);
+
+  write_int (outfd, newfd);
+  g_free (path);
+}
+
+/* Unprivileged side. */
+int
+setgid_io_close (int fd)
+{
+  write_cmd (cmd_close);
+  write_int (setgid_io_outfd, fd);
+
+  return read_int (setgid_io_infd);
+}
+
+/* Privileged side. */
+static void
+setgid_io_close_priv (int outfd, int infd)
+{
+  int fd;
+  int result;
+
+  fd = read_int (infd);
+
+  result = close (fd);
+
+  write_int (outfd, result);
+}
+
+/* Unprivileged side. */
+int
+setgid_io_read (int fd, char *buffer, int n)
+{
+  int result;
+
+  write_cmd (cmd_read);
+  write_int (setgid_io_outfd, fd);
+  write_int (setgid_io_outfd, n);
+
+  result = read_int (setgid_io_infd);
+
+  if ((result >= 0) && (result <= n)) {
+    read_n_bytes (setgid_io_infd, buffer, result);
+  }
+
+  return result;
+}
+
+/* Privileged side. */
+static void
+setgid_io_read_priv (int outfd, int infd)
+{
+  int fd;
+  int n;
+  int result;
+  char *buffer;
+
+  fd = read_int (infd);
+  n = read_int (infd);
+
+  buffer = g_malloc (n);
+  result = read (fd, buffer, n);
+  write_int (outfd, result);
+  if ((result >= 0) && (result <= n)) {
+    write_n_bytes (outfd, buffer, result);
+  }
+  g_free (buffer);
+}
+
+/* Unprivileged side. */
+int
+setgid_io_write (int fd, const char *buffer, int n)
+{
+  write_cmd (cmd_write);
+  write_int (setgid_io_outfd, fd);
+  write_int (setgid_io_outfd, n);
+  write_n_bytes (setgid_io_outfd, buffer, n);
+
+  return read_int (setgid_io_infd);
+}
+
+/* Privileged side. */
+static void
+setgid_io_write_priv (int outfd, int infd)
+{
+  int fd;
+  int n;
+  int result;
+  char *buffer;
+
+  fd = read_int (infd);
+  n = read_int (infd);
+
+  buffer = g_malloc (n);
+  read_n_bytes (infd, buffer, n);
+
+  result = write (fd, buffer, n);
+  write_int (outfd, result);
+
+  g_free (buffer);
+}
+
+/* Unprivileged side. */
+off_t
+setgid_io_seek (int fd, off_t offset, int whence)
+{
+  write_cmd (cmd_seek);
+  write_int (setgid_io_outfd, fd);
+  write_off_t (setgid_io_outfd, offset);
+  write_int (setgid_io_outfd, whence);
+
+  return read_off_t (setgid_io_infd);
+}
+
+/* Privileged side. */
+static void
+setgid_io_seek_priv (int outfd, int infd)
+{
+  int fd;
+  off_t offset;
+  int whence;
+  off_t result;
+
+  fd = read_int (infd);
+  offset = read_off_t (infd);
+  whence = read_int (infd);
+
+  result = lseek (fd, offset, whence);
+
+  write_off_t (outfd, result);
+}
+
+/* Unprivileged side. */
+int
+setgid_io_lock (int fd)
+{
+  write_cmd (cmd_lock);
+  write_int (setgid_io_outfd, fd);
+
+  return read_int (setgid_io_infd);
+}
+
+/* Privileged side. */
+static void
+setgid_io_lock_priv (int outfd, int infd)
+{
+  int fd;
+  int result;
+  struct flock lock;
+
+  fd = read_int (infd);
+
+  lock.l_type = F_WRLCK;
+  lock.l_whence = SEEK_SET;
+  lock.l_start = 0;
+  lock.l_len = 0;
+
+  result = fcntl (fd, F_SETLKW, &lock);
+
+  write_int (outfd, result);
+}
+
+/* Unprivileged side. */
+int
+setgid_io_unlock (int fd)
+{
+  write_cmd (cmd_unlock);
+  write_int (setgid_io_outfd, fd);
+
+  return read_int (setgid_io_infd);
+}
+
+/* Privileged side. */
+static void
+setgid_io_unlock_priv (int outfd, int infd)
+{
+  int fd;
+  int result;
+  struct flock lock;
+
+  fd = read_int (infd);
+
+  lock.l_type = F_UNLCK;
+  lock.l_whence = SEEK_SET;
+  lock.l_start = 0;
+  lock.l_len = 0;
+
+  result = fcntl (fd, F_SETLKW, &lock);
+
+  write_int (outfd, result);
+}
+
+/* Unprivileged side. */
+int
+setgid_io_stat (char *filename, struct stat *buffer)
+{
+  int length;
+
+  write_cmd (cmd_stat);
+
+  length = strlen (filename) + 1;
+  write_int (setgid_io_outfd, length);
+  write_n_bytes (setgid_io_outfd, filename, length);
+
+  read_n_bytes (setgid_io_infd, (char *) buffer, sizeof (struct stat));
+  return read_int (setgid_io_infd);
+}
+
+/* Privileged side. */
+static void
+setgid_io_stat_priv (int outfd, int infd)
+{
+  int length;
+  char *filename;
+  int result;
+  struct stat buffer;
+
+  length = read_int (infd);
+  filename = g_malloc (length);
+  read_n_bytes (infd, filename, length);
+
+  result = stat (filename, &buffer);
+
+  write_n_bytes (outfd, (char *) &buffer, sizeof (struct stat));
+  write_int (outfd, result);
+}
+
+/* Unprivileged side. */
+int
+setgid_io_truncate (int fd, int length)
+{
+  write_cmd (cmd_truncate);
+  write_int (setgid_io_outfd, fd);
+  write_int (setgid_io_outfd, length);
+
+  return read_int (setgid_io_infd);
+}
+
+/* Privileged side. */
+static void
+setgid_io_truncate_priv (int outfd, int infd)
+{
+  int fd;
+  int length;
+  int result;
+
+  fd = read_int (infd);
+  length = read_int (infd);
+  result = ftruncate (fd, length);
+
+  write_int (outfd, result);
+}
+
+G_GNUC_NORETURN
+static void
+setgid_io_pipe_watcher (int outfd, int infd)
+{
+  fd_set watchfds;
+  char command;
+  int cnt;
+
+  FD_ZERO (&watchfds);
+  FD_SET (infd, &watchfds);
+
+  while (1) {
+    select (infd + 1, &watchfds, NULL, NULL, NULL);
+    cnt = read (infd, &command, 1);
+    if (cnt == 1) {
+      switch (command) {
+      case cmd_open:
+       setgid_io_open_priv (outfd, infd);
+       break;
+      case cmd_close:
+       setgid_io_close_priv (outfd, infd);
+       break;
+      case cmd_read:
+       setgid_io_read_priv (outfd, infd);
+       break;
+      case cmd_write:
+       setgid_io_write_priv (outfd, infd);
+       break;
+      case cmd_seek:
+       setgid_io_seek_priv (outfd, infd);
+       break;
+      case cmd_lock:
+       setgid_io_lock_priv (outfd, infd);
+       break;
+      case cmd_unlock:
+       setgid_io_unlock_priv (outfd, infd);
+       break;
+      case cmd_stat:
+       setgid_io_stat_priv (outfd, infd);
+       break;
+      case cmd_truncate:
+       setgid_io_truncate_priv (outfd, infd);
+       break;
+      default:
+       g_warning ("Invalid command to setgid_io: ignored.\n");
+      }
+    } else {
+      exit (0);
+    }
+  }
+}
+
+void
+setgid_io_init (void)
+{
+  gid_t safegid;
+  int setgid_io_inpipe[2];
+  int setgid_io_outpipe[2];
+
+  if (setgid_io_initialised)
+    return;
+
+  if (pipe (setgid_io_inpipe) != 0){
+    g_warning("Unable to create pipe");
+  }
+  if (pipe (setgid_io_outpipe) != 0){
+    g_warning("Unable to create pipe");
+  }
+
+  if ((setgid_io_child_pid = fork ()) != 0) {
+    close (setgid_io_inpipe[1]);
+    close (setgid_io_outpipe[0]);
+
+    setgid_io_infd = setgid_io_inpipe[0];
+    setgid_io_outfd = setgid_io_outpipe[1];
+
+    safegid = getgid ();
+    setregid (safegid, safegid);
+  } else {
+    close (setgid_io_inpipe[0]);
+    close (setgid_io_outpipe[1]);
+    close (STDIN_FILENO);
+
+    setgid_io_pipe_watcher (setgid_io_inpipe[1], setgid_io_outpipe[0]);
+    /* We should never, ever, reach here. */
+    g_assert_not_reached ();
+  }
+
+  setgid_io_initialised = 1;
+}
diff --git a/src/games-setgid-io.h b/src/games-setgid-io.h
new file mode 100644
index 0000000..f6fa4a0
--- /dev/null
+++ b/src/games-setgid-io.h
@@ -0,0 +1,38 @@
+/* games-setgid-io.h : Routines to perform I/O in a seperate setgid
+ *                     subprocess.
+ *
+ * Copyright (C) 2005 by Callum McKenzie
+ *
+ * Time-stamp: <2005-12-18 12:17:26 callum>
+ */
+
+
+#ifndef GAMES_SETGID_IO_H
+#define GAMES_SETGID_IO_H
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+void  setgid_io_init     (void);
+int   setgid_io_open     (const char *path,
+                          int flags);
+int   setgid_io_close    (int fd);
+int   setgid_io_read     (int fd,
+                          char *buffer,
+                          int n);
+int   setgid_io_write    (int fd,
+                          const char *buffer,
+                          int n);
+off_t setgid_io_seek     (int fd,
+                          off_t offset,
+                          int whence);
+int   setgid_io_lock     (int fd);
+int   setgid_io_unlock   (int fd);
+int   setgid_io_stat     (char *filename,
+                          struct stat *buffer);
+int   setgid_io_truncate (int fd,
+                          int length);
+
+#endif /* GAMES_SETGID_IO_H */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]