Hi all,

I made a try to implement a basic way of socket servers  (pfinet and
pflocal) overriding, as described below. Comments are solicited.

1) Add two new environment variables: SERVERS_SOCKET_LOCAL for the pf_local
socket server and SERVERS_SOCKET_INET for the pf_inet server. The value of
each variable should be set to a colon-separated list, and each element of
the list is a file path that specifies a overriding server.

2) Hack *_hurd_socket_server* in "hurd/hurdsock.c" of Glibc to check for the
two environment variables.
For example, when looking up the socket server of pf_inet domain, *
_hurd_socket_server* first checks SERVERS_SOCKET_INET:
   (1) if SERVERS_SOCKET_INET is not set or is set to null, then just
queries and returns the port of the default pf_inet server as usual;
   (2) or else, repeatedly tries querying each overriding server in the
server list defined by SERVERS_SOCKET_INET, until the first existing
overriding server is found (or none is found).

Two limitations of the implementation (which I think are not important) are:
(1) Since the library keeps all the server socket ports it has ever looked
up, changes of the environmental variables after socket
ports initiation will not take effect.

(2)  *_hurd_socket_server* just try to find the first exsiting overriding
server, but can not check whether the server is a correct socket server to
skip invalid ones and try others behind (of course, the socket interface can
always notify the user if current socket server is invalid).

I am also not quite sure on two issues:
(1) Should we disable the overrding mechanism for SUID or SGID processes (
e.g. substituting *__secure_getenv* for *getenv*).

(2) If all overriding servers in the list are not present, need we return
another error than EPFNOSUPPORT (I think it is enough to remind the user,
though it means "Protocol family not supported". The libc interface will
notify the user "Bad file descriptor") used previously when the default
server is absent?

The modified hurd/hurdsock.c is attached to this mail. I have tested it with
Glibc-2.5.

Regards,

Wei Shen
/* _hurd_socket_server - Find the server for a socket domain.
   Copyright (C) 1991,92,93,94,95,97,99 Free Software Foundation, Inc.
   This file is part of the GNU C Library.

   The GNU C 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.1 of the License, or (at your option) any later version.

   The GNU C 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 the GNU C Library; if not, write to the Free
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   02111-1307 USA.  */

#include <hurd.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include <hurd/paths.h>
#include <stdio.h>
#include "stdio-common/_itoa.h"
#include <cthreads.h>           /* For `struct mutex'.  */
#include "hurdmalloc.h"         /* XXX */

static struct mutex lock;

static file_t *servers;
static int max_domain = -1;

/* Return a port to the socket server for DOMAIN.
   Socket servers translate nodes in the directory _SERVERS_SOCKET
   (canonically /servers/socket).  These naming point nodes are named
   by the simplest decimal representation of the socket domain number,
   for example "/servers/socket/3".

   Socket servers are assumed not to change very often.
   The library keeps all the server socket ports it has ever looked up,
   and does not look them up in /servers/socket more than once.  */

socket_t
_hurd_socket_server (int domain, int dead)
{
  socket_t server;

  HURD_CRITICAL_BEGIN;
  __mutex_lock (&lock);

  if (domain > max_domain)
    {
      error_t save = errno;
      file_t *new = realloc (servers, (domain + 1) * sizeof (file_t));
      if (new != NULL)
        {
          do
            new[++max_domain] = MACH_PORT_NULL;
          while (max_domain < domain);
          servers = new;
        }
      else
        /* No space to cache the port; we will just fetch it anew below.  */
        errno = save;
    }

  if (dead && domain <= max_domain)
    {
      /* The user says the port we returned earlier (now in SERVERS[DOMAIN])
         was dead.  Clear the cache and fetch a new one below.  */
      __mach_port_deallocate (__mach_task_self (), servers[domain]);
      servers[domain] = MACH_PORT_NULL;
    }

  if (domain > max_domain || servers[domain] == MACH_PORT_NULL)
    {
      char *serverlist;
      switch (domain)
        {
          case PF_LOCAL:
            serverlist = getenv("SERVERS_SOCKET_LOCAL");
            break;
          case PF_INET:
            serverlist = getenv("SERVERS_SOCKET_INET");
            break;
          default:
            serverlist = NULL;
            break;
        }
      if (serverlist && *serverlist)
        {
          char *tryname;
          serverlist = strdupa(serverlist);
          tryname = strsep(&serverlist, ":");
          do
            server = __file_name_lookup(tryname, 0, 0);
          while (server == MACH_PORT_NULL &&
                 (tryname = strsep(&serverlist, ":")));
        }
      else
        {
          char name[sizeof (_SERVERS_SOCKET) + 100];
          char *np = &name[sizeof (name)];
          *--np = '\0';
          np = _itoa (domain, np, 10, 0);
          *--np = '/';
          np -= sizeof (_SERVERS_SOCKET) - 1;
          memcpy (np, _SERVERS_SOCKET, sizeof (_SERVERS_SOCKET) - 1);
          server = __file_name_lookup (np, 0, 0);
        }
      if (domain <= max_domain)
        servers[domain] = server;
    }
  else
    server = servers[domain];

  if (server == MACH_PORT_NULL && errno == ENOENT)
    /* If the server node is absent, we don't support that protocol.  */
    errno = EPFNOSUPPORT;

  __mutex_unlock (&lock);
  HURD_CRITICAL_END;

  return server;
}

static void
init (void)
{
  int i;

  __mutex_init (&lock);

  for (i = 0; i < max_domain; ++i)
    servers[i] = MACH_PORT_NULL;

  (void) &init;                 /* Avoid "defined but not used" warning.  */
}
text_set_element (_hurd_preinit_hook, init);
_______________________________________________
Bug-hurd mailing list
Bug-hurd@gnu.org
http://lists.gnu.org/mailman/listinfo/bug-hurd

Reply via email to