Esempio n. 1
0
error_t
_treefs_s_fsys_getroot (struct treefs_fsys *fsys,
			mach_port_t dotdot,
			uid_t *uids, unsigned nuids,
			uid_t *gids, unsigned ngids,
			int flags, retry_type *retry, char *retry_name,
			file_t *result, mach_msg_type_name_t *result_type)
{
  error_t err;
  mode_t type;
  struct treefs_node *root;
  struct treefs_auth *auth;

  flags &= O_HURD;

  err = treefs_fsys_get_root (fsys, &root);
  if (err)
    return err;

  if (!(flags & O_NOTRANS))
    /* Try starting up any translator on the root node.  */
    {
      fsys_t child_fsys;

      do
	{
	  err =
	    treefs_node_get_active_trans (root, 0, 0, &dotdot, &child_fsys);
	  if (err == 0 && child_fsys != MACH_PORT_NULL)
	    /* We think there's an active translator; try contacting it.  */
	    {
	      err =
		fsys_getroot (child_fsys, dotdot, MACH_MSG_TYPE_COPY_SEND,
			      uids, nuids, gids, ngids,
			      flags, retry, retry_name, result);
	      /* If we got MACH_SEND_INVALID_DEST or MIG_SERVER_DIED, then
		 the server is dead.  Zero out the old control port and try
		 everything again.  */
	      if (err == MACH_SEND_INVALID_DEST || err == EMIG_SERVER_DIED)
		treefs_node_drop_active_trans (root, control_port);
	    }
	}
      while (err == MACH_SEND_INVALID_DEST || err == MIG_SERVER_DIED);

      /* If we got a translator, or an error trying, return immediately.  */
      if (err || child_fsys)
	{
	  if (!err && *result != MACH_PORT_NULL)
	    *result_type = MACH_MSG_TYPE_MOVE_SEND;
	  else
	    *result_type = MACH_MSG_TYPE_COPY_SEND;

	  if (!err)
	    mach_port_deallocate (mach_task_self (), dotdot);
	  treefs_node_unref (root);

	  return err;
	}
    }

  pthread_mutex_lock (&root->lock);

  type = treefs_node_type (root);
  if (type == S_IFLNK && !(flags & (O_NOLINK | O_NOTRANS)))
    /* Handle symlink interpretation */
    {
      int sym_len = 1000;
      char path_buf[sym_len + 1], *path = path_buf;

      err = treefs_node_get_symlink (root, path, &sym_len);
      if (err == E2BIG)
	/* Symlink contents won't fit in our buffer, so
	   reallocate it and try again.  */
	{
	  path = alloca (sym_len + 1);
	  err = treefs_node_get_symlink (node, path, &sym_len);
	}

      if (err)
	goto out;
      
      if (*path == '/')
	{
	  *retry = FS_RETRY_MAGICAL;
	  *result = MACH_PORT_NULL;
	  *result_type = MACH_MSG_TYPE_COPY_SEND;
	  mach_port_deallocate (mach_task_self (), dotdot);
	}
      else
	{
	  *retry = FS_RETRY_REAUTH;
	  *result = dotdot;
	  *result_type = MACH_MSG_TYPE_COPY_SEND;
	}

      strcpy (retry_name, path);
      goto out;
    }
  
  err = treefs_node_create_auth (root, uids, nuids, gids, ngids, &auth);
  if (err)
    goto out;

  *retry = FS_RETRY_NORMAL;
  *retry_name = '\0';
  *result_type = MACH_MSG_TYPE_MAKE_SEND;

  err = treefs_node_create_right (root, dotdot, flags, auth, result);

  treefs_node_auth_unref (root, auth);

 out:
  treefs_node_release (root);

  return err;
}
Esempio n. 2
0
/*Traces the translator stack on the given underlying node until it
  finds the first translator called `name` and returns the port
  pointing to the translator sitting under this one.*/
error_t
  trace_find
  (mach_port_t underlying, const char *name, int flags, mach_port_t * port)
{
  error_t err = 0;

  /*Identity information about the current process */
  uid_t *uids;
  size_t nuids;

  gid_t *gids;
  size_t ngids;

  /*The name and arguments of the translator being passed now */
  char *argz = NULL;
  size_t argz_len = 0;

  /*The current working directory */
  char *cwd = NULL;

  /*The port to the directory containing the file pointed to by `underlying` */
  file_t dir;

  /*The unauthenticated version of `dir` */
  file_t unauth_dir;

  /*The control port of the current translator */
  fsys_t fsys;

  /*The port to the translator we are currently looking at */
  mach_port_t node = underlying;

  /*The port to the previous translator */
  mach_port_t prev_node = MACH_PORT_NULL;

  /*The retry name and retry type returned by fsys_getroot */
  string_t retry_name;
  retry_type retry;

  /*Finalizes the execution of this function */
  void finalize (void)
  {
    /*If there is a working directory, free it */
    if (cwd)
      free (cwd);

    /*If the ports to the directory exist */
    if (dir)
      PORT_DEALLOC (dir);
  }				/*finalize */

  /*Obtain the current working directory */
  cwd = getcwd (NULL, 0);
  if (!cwd)
    {
      LOG_MSG ("trace_find: Could not obtain cwd.");
      return EINVAL;
    }
  LOG_MSG ("trace_find: cwd: '%s'", cwd);

  /*Open a port to this directory */
  dir = file_name_lookup (cwd, 0, 0);
  if (!dir)
    {
      finalize ();
      return ENOENT;
    }

  /*Try to get the number of effective UIDs */
  nuids = geteuids (0, 0);
  if (nuids < 0)
    {
      finalize ();
      return EINVAL;
    }

  /*Allocate some memory for the UIDs on the stack */
  uids = alloca (nuids * sizeof (uid_t));

  /*Fetch the UIDs themselves */
  nuids = geteuids (nuids, uids);
  if (nuids < 0)
    {
      finalize ();
      return EINVAL;
    }

  /*Try to get the number of effective GIDs */
  ngids = getgroups (0, 0);
  if (ngids < 0)
    {
      finalize ();
      return EINVAL;
    }

  /*Allocate some memory for the GIDs on the stack */
  gids = alloca (ngids * sizeof (gid_t));

  /*Fetch the GIDs themselves */
  ngids = getgroups (ngids, gids);
  if (ngids < 0)
    {
      finalize ();
      return EINVAL;
    }

  /*Obtain the unauthenticated version of `dir` */
  err = io_restrict_auth (dir, &unauth_dir, 0, 0, 0, 0);
  if (err)
    {
      finalize ();
      return err;
    }

  char buf[256];
  char *_buf = buf;
  size_t len = 256;
  io_read (node, &_buf, &len, 0, len);
  LOG_MSG ("trace_find: Read from underlying: '%s'", buf);

  /*Go up the translator stack */
  for (; !err;)
    {
      /*retreive the name and options of the current translator */
      err = file_get_fs_options (node, &argz, &argz_len);
      if (err)
	break;

      LOG_MSG ("trace_find: Obtained translator '%s'", argz);
      if (strcmp (argz, name) == 0)
	{
	  LOG_MSG ("trace_find: Match. Stopping here.");
	  break;
	}

      /*try to fetch the control port for this translator */
      err = file_get_translator_cntl (node, &fsys);
      LOG_MSG ("trace_find: err = %d", (int) err);
      if (err)
	break;

      LOG_MSG ("trace_find: Translator control port: %lu",
	       (unsigned long) fsys);

      prev_node = node;

      /*fetch the root of the translator */
      err = fsys_getroot
	(fsys, unauth_dir, MACH_MSG_TYPE_COPY_SEND,
	 uids, nuids, gids, ngids,
	 flags | O_NOTRANS, &retry, retry_name, &node);

      LOG_MSG ("trace_find: fsys_getroot returned %d", (int) err);
      LOG_MSG ("trace_find: Translator root: %lu", (unsigned long) node);

      /*TODO: Remove this debug output. */
      /*char buf[256];
         char * _buf = buf;
         size_t len = 256;
         io_read(node, &_buf, &len, 0, len);
         LOG_MSG("trace_find: Read: '%s'", buf); */
    }

  /*If the error occurred (most probably) because of the fact that we
     have reached the top of the translator stack */
  if ((err == EMACH_SEND_INVALID_DEST) || (err == ENXIO))
    /*this is OK */
    err = 0;

  /*Return the port to read from */
  *port = prev_node;

  /*Return the result of operations */
  finalize ();
  return err;
}				/*trace_find */