Example #1
0
int
main (int argc, char **argv)
{
  mach_port_t bootstrap;
  mach_port_t control;
  error_t err;

  /* Parse our options...  */
  argp_parse (&argp, argc, argv, 0, 0, 0);

  task_get_bootstrap_port (mach_task_self (), &bootstrap);
  if (bootstrap == MACH_PORT_NULL)
    error (1, 0, "Must be started as a translator");

  linktarget = argv[1];

  /* Reply to our parent */
  mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE, &control);
  mach_port_insert_right (mach_task_self (), control, control,
			  MACH_MSG_TYPE_MAKE_SEND);
  err =
    fsys_startup (bootstrap, 0, control, MACH_MSG_TYPE_COPY_SEND, &realnode);
  mach_port_deallocate (mach_task_self (), control);
  mach_port_deallocate (mach_task_self (), bootstrap);
  if (err)
    error (1, err, "Starting up translator");

  io_restrict_auth (realnode, &realnodenoauth, 0, 0, 0, 0);
  mach_port_deallocate (mach_task_self (), realnode);

  /* Mark us as important.  */
  mach_port_t proc = getproc ();
  if (proc == MACH_PORT_NULL)
    error (2, err, "cannot get a handle to our process");

  err = proc_mark_important (proc);
  /* This might fail due to permissions or because the old proc server
     is still running, ignore any such errors.  */
  if (err && err != EPERM && err != EMIG_BAD_ID)
    error (2, err, "Cannot mark us as important");

  mach_port_deallocate (mach_task_self (), proc);

  /* Launch */
  while (1)
    {
      /* The timeout here is 10 minutes */
      err = mach_msg_server_timeout (fsys_server, 0, control,
				     MACH_RCV_TIMEOUT, 1000 * 60 * 10);
      if (err == MACH_RCV_TIMED_OUT)
	exit (0);
    }
}
kern_return_t
trivfs_S_io_restrict_auth (struct trivfs_protid *cred,
			   mach_port_t reply,
			   mach_msg_type_name_t replytype,
			   mach_port_t *newport,
			   mach_msg_type_name_t *newporttype,
			   uid_t *uids, size_t nuids,
			   uid_t *gids, size_t ngids)
{
  int i;
  error_t err;
  struct trivfs_protid *newcred;
  struct idvec *uvec, *gvec;
  struct iouser *user;

  if (!cred)
    return EOPNOTSUPP;

  if (cred->isroot)
    /* CRED has root access, and so may use any ids.  */
    {
      err = iohelp_create_complex_iouser (&user, uids, nuids, gids, ngids);
      if (err)
        return err;
    }
  else
    {
      uvec = make_idvec ();
      if (! uvec)
        return ENOMEM;

      gvec = make_idvec ();
      if (! gvec)
        {
	  idvec_free (uvec);
	  return ENOMEM;
	}

      /* Otherwise, use any of the requested ids that CRED already has.  */
      for (i = 0; i < cred->user->uids->num; i++)
	if (listmember (uids, cred->user->uids->ids[i], nuids))
	  {
	    err = idvec_add (uvec, cred->user->uids->ids[i]);
	    if (err)
	      goto out;
	  }

      for (i = 0; i < cred->user->gids->num; i++)
	if (listmember (gids, cred->user->gids->ids[i], ngids))
	  {
	    err = idvec_add (gvec, cred->user->gids->ids[i]);
	    if (err)
	      goto out;
	  }

      err = iohelp_create_iouser (&user, uvec, gvec);
      if (err)
        {
	out:
	  idvec_free (uvec);
	  idvec_free (gvec);
	  return err;
	}
    }

  err = ports_create_port (cred->po->cntl->protid_class,
			   cred->po->cntl->protid_bucket,
			   sizeof (struct trivfs_protid),
			   &newcred);
  if (err)
    {
      iohelp_free_iouser (user);
      return err;
    }

  newcred->isroot = 0;
  mutex_lock (&cred->po->cntl->lock);
  newcred->po = cred->po;
  newcred->po->refcnt++;
  mutex_unlock (&cred->po->cntl->lock);
  if (cred->isroot && idvec_contains (user->uids, 0))
    newcred->isroot = 1;
  newcred->user = user;
  newcred->hook = cred->hook;

  err = io_restrict_auth (cred->realnode, &newcred->realnode,
			  user->uids->ids, user->uids->num,
			  user->gids->ids, user->gids->num);
  if (!err && trivfs_protid_create_hook)
    {
      err = (*trivfs_protid_create_hook) (newcred);
      if (err)
	mach_port_deallocate (mach_task_self (), newcred->realnode);
    }

  if (err)
    /* Signal that the user destroy hook shouldn't be called on NEWCRED.  */
    newcred->realnode = MACH_PORT_NULL;
  else
    {
      *newport = ports_get_right (newcred);
      *newporttype = MACH_MSG_TYPE_MAKE_SEND;
    }

  /* This will destroy NEWCRED if we got an error and didn't do the
     ports_get_right above.  */
  ports_port_deref (newcred);

  return 0;
}
Example #3
0
kern_return_t
trivfs_S_fsys_getroot (struct trivfs_control *cntl,
		       mach_port_t reply_port,
		       mach_msg_type_name_t reply_port_type,
		       mach_port_t dotdot,
		       uid_t *uids, size_t nuids,
		       uid_t *gids, size_t ngids,
		       int flags,
		       retry_type *do_retry,
		       char *retry_name,
		       mach_port_t *newpt,
		       mach_msg_type_name_t *newpttype)
{
  int perms;
  error_t err = 0;
  mach_port_t new_realnode;
  struct trivfs_protid *cred;
  struct iouser *user;

  if (!cntl)
    return EOPNOTSUPP;

  if (trivfs_getroot_hook)
    {
      err = (*trivfs_getroot_hook) (cntl, reply_port, reply_port_type, dotdot,
				    uids, nuids, gids, ngids, flags,
				    do_retry, retry_name, newpt, newpttype);
      if (err != EAGAIN)
	return err;
    }

  if ((flags & O_WRITE & trivfs_allow_open) != (flags & O_WRITE))
    return EROFS;
  if ((flags & (O_READ|O_WRITE|O_EXEC) & trivfs_allow_open)
      != (flags & (O_READ|O_WRITE|O_EXEC)))
    return EACCES;

  /* O_CREAT and O_EXCL are not meaningful here; O_NOLINK and O_NOTRANS
     will only be useful when trivfs supports translators (which it doesn't
     now). */
  flags &= O_HURD;
  flags &= ~(O_CREAT|O_EXCL|O_NOLINK|O_NOTRANS);

  struct idvec idvec = {
    .ids = uids,
    .num = nuids,
    .alloced = nuids,
  };

  if (_is_privileged (&idvec))
    /* Privileged users should be given all our rights.  */
    err = io_duplicate (cntl->underlying, &new_realnode);
  else
    /* Non-privileged, restrict rights.  */
    err = io_restrict_auth (cntl->underlying,
			    &new_realnode, uids, nuids, gids, ngids);

  if (err)
    return err;

  err = iohelp_create_complex_iouser (&user, uids, nuids, gids, ngids);
  if (err)
    return err;

  /* Validate permissions.  */
  if (! trivfs_check_access_hook)
    file_check_access (new_realnode, &perms);
  else
    (*trivfs_check_access_hook) (cntl, user, new_realnode, &perms);
  if ((flags & (O_READ|O_WRITE|O_EXEC) & perms)
      != (flags & (O_READ|O_WRITE|O_EXEC)))
    err = EACCES;

  if (!err && trivfs_check_open_hook)
    err = (*trivfs_check_open_hook) (cntl, user, flags);
  if (!err)
    {
      if (! trivfs_open_hook)
	{
	  err = trivfs_open (cntl, user, flags, new_realnode, &cred);
	  if (!err)
	    mach_port_deallocate (mach_task_self (), dotdot);
	}
      else
	err = (*trivfs_open_hook) (cntl, user, dotdot, flags, new_realnode,
				   &cred);
    }

  if (err)
    {
      mach_port_deallocate (mach_task_self (), new_realnode);
      iohelp_free_iouser (user);
    }
  else
    {
      *do_retry = FS_RETRY_NORMAL;
      *retry_name = '\0';
      *newpt = ports_get_right (cred);
      *newpttype = MACH_MSG_TYPE_MAKE_SEND;
      ports_port_deref (cred);
    }

  return err;
}
Example #4
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 */