Logo Search packages:      
Sourcecode: netapplet version File versions  Download package

netcommon.c

/*
 * src/netcommon.c - methods common to both netapplet and netdaemon
 *
 * Copyright (C) 2004 Novell, Inc.
 *
 * Licensed under the GNU GPL v2.  See COPYING
 */

#include <string.h>
#include <stdio.h>
#include <sys/socket.h>
#include <unistd.h>

#include "netcommon.h"

//#define NETCOMMON_DEBUG

#ifdef NETCOMMON_DEBUG
# include <time.h>
# define dbg(fmt,arg...) fprintf(stderr, "%ld: " fmt, time (NULL), ##arg)
#else
# define dbg(fmt,arg...) do { } while(0)
#endif

/*
 * Check general strings for sanity.  Used for ESSID's and keys.  We allow
 * spaces, alphanumerics, and a few special characters.
 */
const char *
netcommon_verify_string (const char *str)
{
      const char *s = str;

      if (!str || *s == '\0')
            return str;

      do {
            if (!g_ascii_isalnum (*s) && *s != ' ' && *s != '.' &&
                        *s != '-' && *s != '_')
                  return NULL;
      } while (*++s != '\0');

      return str;
}

#define GENTOO_RELEASE_FILE   "/etc/gentoo-release"
#define GENTOO_RELEASE_PREFIX "Gentoo"
#define SUSE_RELEASE_FILE     "/etc/SuSE-release"
#define SUSE_RELEASE_PREFIX   "SuSE"
#define DEBIAN_RELEASE_FILE     "/etc/debian_version"

static GIOStatus
netcommon_write_chars_all (GIOChannel *channel, const char *buf,
                     gssize count, GError **err)
{
      int size;
      gssize total_written = 0;
      gsize bytes_written;
      GIOStatus ret;

      if (count == -1)
            size = strlen (buf);
      else
            size = count;

      do {
            ret = g_io_channel_write_chars (channel,
                                    buf + total_written,
                                    size - total_written,
                                    &bytes_written, err);
            total_written += bytes_written;
      } while (total_written < size &&
             (err == NULL || *err == NULL) &&
             ret != G_IO_STATUS_ERROR &&
             ret != G_IO_STATUS_EOF);

      g_io_channel_flush (channel, NULL);

      return ret;
}

void
netcommon_send_message (GIOChannel *channel, const char *command, ...)
{
      GString *str;
      va_list args;
      const char *a;

      str = g_string_new (command);

      va_start (args, command);

      a = va_arg (args, const char *);
      while (a != NULL) {
            str = g_string_append_c (str, ' ');
            str = g_string_append (str, a);

            a = va_arg (args, const char *);
      }

      va_end (args);

      str = g_string_append_c (str, '\n');

      dbg ("outgoing: %s", str->str);

      netcommon_write_chars_all (channel, str->str, str->len, NULL);

      g_string_free (str, TRUE);
}

typedef void (*do_func_t) (GIOChannel *, char **);

static void
netcommon_parse_cmd (const char *cmd, GIOChannel *channel, GHashTable *hash)
{
      char **split, **iter, **tokens;
      int i;
      do_func_t f;

      dbg ("incoming: %s\n", cmd);

      split = g_strsplit (cmd, " ", 0);
      for (i = 0; split[i] != NULL; i++);

      tokens = g_new0 (char *, i + 1);
      
      i = 0;
      for (iter = split; *iter; iter++) {
            int len;
            char *tmp;
            gboolean inc = FALSE;

            len = strlen (*iter);

            if ((*iter)[len - 1] != '\\') {
                  tmp = g_strdup (*iter);
                  inc = TRUE;
            } else
                  tmp = g_strndup (*iter, len - 1);

            if (tokens[i] != NULL) {
                  char *t;

                  t = g_strconcat (tokens[i], " ", tmp, NULL);

                  g_free (tokens[i]);
                  g_free (tmp);

                  tokens[i] = t;
            } else
                  tokens[i] = tmp;

            if (inc)
                  i++;
      }
      g_strfreev (split);
                  

      f = g_hash_table_lookup (hash, tokens[0]);
      if (f)
            f (channel, tokens);
      g_strfreev (tokens);
}

#define VALID_BINARY BINDIR"/netapplet"

static gboolean
netcommon_read_channel (GIOChannel *source,
                  GIOCondition condition,
                  gpointer user_data)
{
      GHashTable *hash = user_data;
      int sockfd;
      struct ucred cred;
      socklen_t size;
      int rc;
      gboolean authenticated = FALSE;

      sockfd = g_io_channel_unix_get_fd (source);

      size = sizeof (cred);
      rc = getsockopt (sockfd, SOL_SOCKET, SO_PEERCRED, &cred, &size);

      if (rc == 0 && size == sizeof (cred)) {
            if (cred.uid == 0)
                  authenticated = TRUE;
            else {
                  char *path;
                  char link_target[PATH_MAX];
                  int len;

                  path = g_strdup_printf ("/proc/%d/exe", cred.pid);

                  len = readlink (path, link_target, PATH_MAX);

                  if (len >= 0) {
                        link_target[len] = 0;
                        if (strcmp (link_target, VALID_BINARY) == 0)
                              authenticated = TRUE;
                  }

                  g_free (path);
            }
      }

      if (condition & G_IO_IN) {
            GError *error = NULL;
            gsize len, term;
            char *buf;

            g_io_channel_read_line (source, &buf, &len, &term, &error);
            if (error) {
                  g_critical ("Socket read failed: %s\n", error->message);
                  g_error_free (error);
            } else if (!authenticated) {
                  printf ("Received message from unauthenticated "
                        "PID %d\n", cred.pid);
                  netcommon_send_message (source, "unauthorized", NULL);
            } else if (len > 0) {
                  buf[term] = '\0';
                  netcommon_parse_cmd (buf, source, hash);
            }

            g_free (buf);
      }

      /* client hung up on us */
      if (condition & G_IO_HUP)
            return FALSE;

      return TRUE;
}

void
netcommon_watch_channel (GIOChannel *channel, GHashTable *hash)
{
      g_io_add_watch (channel, G_IO_IN | G_IO_HUP,
                  netcommon_read_channel, hash);
}

char *
netcommon_escape_argument (const char *argument)
{
      char **tokens;
      char *escaped;

      tokens = g_strsplit (argument, " ", 0);
      escaped = g_strjoinv ("\\ ", tokens);
      g_strfreev (tokens);

      return escaped;
}

static gboolean
release_file_has_prefix (gchar *release_file_path, gchar *release_file_prefix)
{
      GError *err = NULL;
      GIOChannel *release_file;
      gchar *release_filedata;
      gboolean release_file_matches = FALSE;
 
        /* Open release file and compare prefix to string arg */
        release_file = g_io_channel_new_file (release_file_path, "r", &err);
        if (release_file) {
            if (g_io_channel_read_line (release_file, &release_filedata, NULL, NULL, &err) ==
                                  G_IO_STATUS_NORMAL) {
                  if (g_str_has_prefix (release_filedata, release_file_prefix)) {
                        release_file_matches = TRUE;
                  }
            }
            else {
                  g_error_free (err);
            }

      }
      else {
            g_error_free (err);
      }

      return release_file_matches; 
}

static gboolean
check_gentoo (void)
{
      return release_file_has_prefix (GENTOO_RELEASE_FILE, GENTOO_RELEASE_PREFIX);
}

static gboolean
check_debian (void)
{
        if (! access (DEBIAN_RELEASE_FILE, F_OK))
        return TRUE;
      else
        return FALSE;
}

static gboolean 
check_suse (void)
{
      return release_file_has_prefix (SUSE_RELEASE_FILE, SUSE_RELEASE_PREFIX);
}

gchar *
get_platform (void)
{
      gchar *platform = NULL;

      if (check_suse ())
            return platform = SUSE_PLATFORM_NAME;
      if (check_gentoo ())
            return platform = GENTOO_PLATFORM_NAME; 
      if (check_debian ())
              return platform = DEBIAN_PLATFORM_NAME;
      return platform;
}

Generated by  Doxygen 1.6.0   Back to index