Example #1
0
/* Return the login name of the user, or NULL if it can't be determined.
   The returned pointer, if not NULL, is good only until the next call.  */
char *
getlogin (void)
{
  static char login[1024];	/* XXX */
  error_t err;

  if (err = __USEPORT (PROC, __proc_getlogin (port, login)))
    {
      errno = err;
      return NULL;
    }

  return login;
}
error_t
_hurd_check_ids (void)
{
  if (! _hurd_id.valid)
    {
      inline void dealloc (__typeof (_hurd_id.gen) *p)
	{
	  if (p->uids)
	    {
	      __vm_deallocate (__mach_task_self (),
			       (vm_address_t) p->uids,
			       p->nuids * sizeof (uid_t));
	      p->uids = NULL;
	    }
	  p->nuids = 0;
	  if (p->gids)
	    {
	      __vm_deallocate (__mach_task_self (),
			       (vm_address_t) p->gids,
			       p->ngids * sizeof (gid_t));
	      p->gids = NULL;
	    }
	  p->ngids = 0;
	}

      error_t err;

      dealloc (&_hurd_id.gen);
      dealloc (&_hurd_id.aux);

      if (_hurd_id.rid_auth != MACH_PORT_NULL)
	{
	  __mach_port_deallocate (__mach_task_self (), _hurd_id.rid_auth);
	  _hurd_id.rid_auth = MACH_PORT_NULL;
	}

      if (err = __USEPORT (AUTH, __auth_getids
			   (port,
			    &_hurd_id.gen.uids, &_hurd_id.gen.nuids,
			    &_hurd_id.aux.uids, &_hurd_id.aux.nuids,
			    &_hurd_id.gen.gids, &_hurd_id.gen.ngids,
			    &_hurd_id.aux.gids, &_hurd_id.aux.ngids)))
	return err;

      _hurd_id.valid = 1;
    }

  return 0;
}
Example #3
0
error_t
__hurd_invoke_translator (file_t file, int flags, file_t *newport)
{
  error_t err;
  enum retry_type doretry;
  char retryname[1024];		/* XXX string_t LOSES! */

  err = __file_invoke_translator (file, flags, &doretry, retryname, newport);

  if (! err)
    err = __USEPORT (CRDIR, __hurd_file_name_lookup_retry (port,
							   doretry, retryname,
							   flags, 0, newport));

  return err;
}
/* Create a new session with the calling process as its leader.
   The process group IDs of the session and the calling process
   are set to the process ID of the calling process, which is returned.  */
pid_t
__setsid (void)
{
  error_t err;
  unsigned int stamp;

  HURD_CRITICAL_BEGIN;
  __mutex_lock (&_hurd_dtable_lock);

  stamp = _hurd_pids_changed_stamp; /* Atomic fetch.  */

  /* Tell the proc server we want to start a new session.  */
  err = __USEPORT (PROC, __proc_setsid (port));
  if (err)
    __mutex_unlock (&_hurd_dtable_lock);
  else
    {
      /* Punt our current ctty, and update the dtable accordingly.  We hold
	 the dtable lock from before the proc_setsid call through clearing
	 the cttyid port and processing the dtable, so that we can be sure
	 that it's all done by the time the signal thread processes the
	 pgrp change notification.  */
      _hurd_locked_install_cttyid (MACH_PORT_NULL);

      /* Synchronize with the signal thread to make sure we have received
	 and processed proc_newids before returning to the user.
	 This is necessary to ensure that _hurd_pgrp (and thus the value
	 returned by `getpgrp ()' in other threads) has been updated before
	 we return.  */
      while (_hurd_pids_changed_stamp == stamp)
	{
#ifdef noteven
	  /* XXX we have no need for a mutex, but cthreads demands one.  */
	  __condition_wait (&_hurd_pids_changed_sync, NULL);
#else
	  __swtch_pri (0);
#endif
	}
    }

  HURD_CRITICAL_END;

  return err ? __hurd_fail (err) : _hurd_pgrp;
}
Example #5
0
kern_return_t
__get_privileged_ports (mach_port_t *host_priv_ptr,
			device_t *device_master_ptr)
{
  if ((host_priv_ptr && _hurd_host_priv == MACH_PORT_NULL)
      || (device_master_ptr && _hurd_device_master == MACH_PORT_NULL))
    {
      error_t err;

      if (_hurd_ports)
	/* We have gotten some initial ports, so perhaps
	   we have a proc server to talk to.  */
	err = __USEPORT (PROC, __proc_getprivports (port,
						    &_hurd_host_priv,
						    &_hurd_device_master));
      else
	return MACH_SEND_INVALID_DEST;

      if (err)
	return err;
    }

  if (host_priv_ptr)
    {
      error_t err = _hurd_host_priv == MACH_PORT_NULL ? 0
	: __mach_port_mod_refs (mach_task_self (),
				_hurd_host_priv, MACH_PORT_RIGHT_SEND, +1);
      if (err)
	return err;
      *host_priv_ptr = _hurd_host_priv;
    }

  if (device_master_ptr)
    {
      error_t err = _hurd_device_master == MACH_PORT_NULL ? 0
	: __mach_port_mod_refs (mach_task_self (),
				_hurd_device_master, MACH_PORT_RIGHT_SEND, +1);
      if (err)
	return err;
      *device_master_ptr = _hurd_device_master;
    }

  return KERN_SUCCESS;
}
Example #6
0
/* Return at most NAME_LEN characters of the login name of the user in NAME.
   If it cannot be determined or some other error occurred, return the error
   code.  Otherwise return 0.  */
int
__getlogin_r (char *name, size_t name_len)
{
  string_t login;
  error_t err;

  if (err = __USEPORT (PROC, __proc_getlogin (port, login)))
    return errno = err;

  size_t len = __strnlen (login, sizeof login - 1) + 1;
  if (len > name_len)
    {
      errno = ERANGE;
      return errno;
    }

  memcpy (name, login, len);
  return 0;
}
int
__uname (struct utsname *uname)
{
  error_t err;

  if (err = __USEPORT (PROC, __proc_uname (port, uname)))
    return __hurd_fail (err);

  /* Fill in the hostname, which the proc server doesn't know.  */
  err = errno;
  if (__gethostname (uname->nodename, sizeof uname->nodename) < 0)
    {
      if (errno == ENAMETOOLONG)
	/* Ignore the error of the buffer being too small.
	   It is of fixed size, nothing to do about it.  */
	errno = err;
      else
	return -1;
    }

  return 0;
}
Example #8
0
void
_hurd_exit (int status)
{
  /* Give the proc server our exit status.  */
  __USEPORT (PROC, __proc_mark_exit (port, status, 0));

  /* Commit suicide.  */
  __task_terminate (__mach_task_self ());

  /* Perhaps the cached mach_task_self was bogus.  */
  __task_terminate ((__mach_task_self) ());

  /* This sucker really doesn't want to die.  */
  while (1)
    {
#ifdef LOSE
      LOSE;
#else
      volatile const int zero = 0, one = 1;
      volatile int lossage = one / zero;
#endif
    }
}
Example #9
0
kern_return_t
_S_msg_describe_ports (mach_port_t msgport, mach_port_t refport,
		       mach_port_t *ports, mach_msg_type_number_t nports,
		       char **desc, mach_msg_type_number_t *desclen)
{
  char *p, *end;

  if (__USEPORT (AUTH, msgport != port))
    return EPERM;

  end = *desc + *desclen;
  p = *desc;
  while (nports-- > 0)
    {
      char this[200];
      describe_port (this, *ports++);
      p = __stpncpy (p, this, end - p);
      if (p == end && p[-1] != '\0')
	return ENOMEM;
    }

  *desclen = p - *desc;
  return 0;
}
Example #10
0
int
__setregid (gid_t rgid, gid_t egid)
{
  auth_t newauth;
  error_t err;

  HURD_CRITICAL_BEGIN;
  __mutex_lock (&_hurd_id.lock);
  err = _hurd_check_ids ();

  if (!err)
    {
      /* Make a new auth handle which has RGID as the real gid,
	 and EGID as the first element in the list of effective gids.  */

      gid_t *newgen, *newaux;
      size_t ngen, naux;

      newgen = _hurd_id.gen.gids;
      ngen = _hurd_id.gen.ngids;
      if (egid != -1)
	{
	  if (_hurd_id.gen.ngids == 0)
	    {
	      /* No effective gids now.  The new set will be just GID.  */
	      newgen = &egid;
	      ngen = 1;
	    }
	  else
	    {
	      _hurd_id.gen.gids[0] = egid;
	      _hurd_id.valid = 0;
	    }
	}

      newaux = _hurd_id.aux.gids;
      naux = _hurd_id.aux.ngids;
      if (rgid != -1)
	{
	  if (_hurd_id.aux.ngids == 0)
	    {
	      newaux = &rgid;
	      naux = 1;
	    }
	  else
	    {
	      _hurd_id.aux.gids[0] = rgid;
	      _hurd_id.valid = 0;
	    }
	}

      err = __USEPORT (AUTH, __auth_makeauth
		       (port, NULL, MACH_MSG_TYPE_COPY_SEND, 0,
			_hurd_id.gen.uids, _hurd_id.gen.nuids,
			_hurd_id.aux.uids, _hurd_id.aux.nuids,
			newgen, ngen, newaux, naux,
			&newauth));
    }
  __mutex_unlock (&_hurd_id.lock);
  HURD_CRITICAL_END;

  if (err)
    return __hurd_fail (err);

  /* Install the new handle and reauthenticate everything.  */
  err = __setauth (newauth);
  __mach_port_deallocate (__mach_task_self (), newauth);
  return err;
}
Example #11
0
/* Set the group ID of the calling process to UID.
   If the calling process is the super-user, the real
   and effective group IDs, and the saved set-group-ID to UID;
   if not, the effective group ID is set to GID.  */
int
__setgid (gid_t gid)
{
  auth_t newauth;
  error_t err;

  HURD_CRITICAL_BEGIN;
  __mutex_lock (&_hurd_id.lock);
  err = _hurd_check_ids ();

  if (!err)
    {
      /* Make a new auth handle which has GID as the real gid,
	 and as the first element in the list of effective gids.  */

      gid_t *newgen, *newaux, auxbuf[2];
      size_t ngen, naux;

      if (_hurd_id.gen.ngids == 0)
	{
	  /* No effective gids now.  The new set will be just GID.  */
	  newgen = &gid;
	  ngen = 1;
	}
      else
	{
	  _hurd_id.gen.gids[0] = gid;
	  _hurd_id.valid = 0;
	  newgen = _hurd_id.gen.gids;
	  ngen = _hurd_id.gen.ngids;
	}

      newaux = _hurd_id.aux.gids;
      naux = _hurd_id.aux.ngids;
      if (_hurd_id.gen.nuids > 0 && _hurd_id.gen.uids[0] == 0)
	{
	  /* We are root; set the real and saved IDs too.  */
	  _hurd_id.valid = 0;
	  if (_hurd_id.aux.ngids < 2)
	    {
	      newaux = auxbuf;
	      naux = 2;
	    }
	  newaux[0] = newaux[1] = gid;
	}

      err = __USEPORT (AUTH, __auth_makeauth
		       (port, NULL, MACH_MSG_TYPE_COPY_SEND, 0,
			_hurd_id.gen.uids, _hurd_id.gen.nuids,
			_hurd_id.aux.uids, _hurd_id.aux.nuids,
			newgen, ngen, newaux, naux,
			&newauth));
    }
  __mutex_unlock (&_hurd_id.lock);
  HURD_CRITICAL_END;

  if (err)
    return __hurd_fail (err);

  /* Install the new handle and reauthenticate everything.  */
  err = __setauth (newauth);
  __mach_port_deallocate (__mach_task_self (), newauth);
  return err;
}
Example #12
0
/* Set the real user ID, effective user ID, and saved-set user ID,
   of the calling process to RUID, EUID, and SUID, respectively.  */
int
__setresuid (uid_t ruid, uid_t euid, uid_t suid)
{
  auth_t newauth;
  error_t err;

  HURD_CRITICAL_BEGIN;
  __mutex_lock (&_hurd_id.lock);
  err = _hurd_check_ids ();

  if (!err)
    {
      /* Make a new auth handle which has EUID as the first element in the
	 list of effective uids.  */

      uid_t *newgen, *newaux;
      uid_t auxs[2] = { ruid, suid };
      size_t ngen, naux;

      newgen = _hurd_id.gen.uids;
      ngen = _hurd_id.gen.nuids;
      if (euid != -1)
	{
	  if (_hurd_id.gen.nuids == 0)
	    {
	      /* No effective uids now.  The new set will be just UID.  */
	      newgen = &euid;
	      ngen = 1;
	    }
	  else
	    {
	      _hurd_id.gen.uids[0] = euid;
	      _hurd_id.valid = 0;
	    }
	}

      newaux = _hurd_id.aux.uids;
      naux = _hurd_id.aux.nuids;
      if (ruid != -1)
	{
	  if (_hurd_id.aux.nuids == 0)
	    {
	      newaux = &ruid;
	      naux = 1;
	    }
	  else
	    {
	      _hurd_id.aux.uids[0] = ruid;
	      _hurd_id.valid = 0;
	    }
	}

      if (suid != -1)
	{
	  if (ruid == -1)
	    {
	      if (_hurd_id.aux.nuids >= 1)
		auxs[0] = _hurd_id.aux.uids[0];
	      else if (_hurd_id.gen.nuids >= 1)
		auxs[0] = _hurd_id.gen.uids[0];
	      else
		/* Not even an effective UID.
                   Fall back to the only UID we have. */
		auxs[0] = suid;
	    }
	  if (_hurd_id.aux.nuids <= 1)
	    {
	      /* No saved uids now.  The new set will be just UID.  */
	      newaux = auxs;
	      naux = 2;
	    }
	  else
	    {
	      _hurd_id.aux.uids[1] = suid;
	      _hurd_id.valid = 0;
	    }
	}

      err = __USEPORT (AUTH, __auth_makeauth
		       (port, NULL, MACH_MSG_TYPE_COPY_SEND, 0,
			newgen, ngen, newaux, naux,
			_hurd_id.gen.gids, _hurd_id.gen.ngids,
			_hurd_id.aux.gids, _hurd_id.aux.ngids,
			&newauth));
    }

  __mutex_unlock (&_hurd_id.lock);
  HURD_CRITICAL_END;

  if (err)
    return __hurd_fail (err);

  /* Install the new handle and reauthenticate everything.  */
  err = __setauth (newauth);
  __mach_port_deallocate (__mach_task_self (), newauth);
  return err;
}
Example #13
0
void
_hurdsig_fault_init (void)
{
  error_t err;
  struct machine_thread_state state;
  mach_port_t sigexc;

  /* Allocate a port to receive signal thread exceptions.
     We will move this receive right to the proc server.  */
  err = __mach_port_allocate (__mach_task_self (),
			      MACH_PORT_RIGHT_RECEIVE, &sigexc);
  assert_perror (err);
  err = __mach_port_allocate (__mach_task_self (),
			      MACH_PORT_RIGHT_RECEIVE, &forward_sigexc);
  assert_perror (err);

  /* Allocate a port to receive the exception msgs forwarded
     from the proc server.  */
  err = __mach_port_insert_right (__mach_task_self (), sigexc,
				  sigexc, MACH_MSG_TYPE_MAKE_SEND);
  assert_perror (err);

  /* Set the queue limit for this port to just one.  The proc server will
     notice if we ever get a second exception while one remains queued and
     unreceived, and decide we are hopelessly buggy.  */
#ifdef MACH_PORT_RECEIVE_STATUS_COUNT
  {
    const mach_port_limits_t lim = { mpl_qlimit: 1 };
    assert (MACH_PORT_RECEIVE_STATUS_COUNT == sizeof lim / sizeof (natural_t));
    err = __mach_port_set_attributes (__mach_task_self (), forward_sigexc,
				      MACH_PORT_RECEIVE_STATUS,
				      (mach_port_info_t) &lim,
				      MACH_PORT_RECEIVE_STATUS_COUNT);
  }
#else
  err = __mach_port_set_qlimit (__mach_task_self (), forward_sigexc, 1);
#endif
  assert_perror (err);

  /* This state will be restored when we fault.
     It runs the function above.  */
  memset (&state, 0, sizeof state);
  MACHINE_THREAD_STATE_SET_PC (&state, faulted);
  MACHINE_THREAD_STATE_SET_SP (&state, faultstack, sizeof faultstack);

  err = __USEPORT
    (PROC,
     __proc_handle_exceptions (port,
			       sigexc,
			       forward_sigexc, MACH_MSG_TYPE_MAKE_SEND,
			       MACHINE_THREAD_STATE_FLAVOR,
			       (natural_t *) &state,
			       MACHINE_THREAD_STATE_COUNT));
  assert_perror (err);

  /* Direct signal thread exceptions to the proc server.  */
#ifdef THREAD_EXCEPTION_PORT
  err = __thread_set_special_port (_hurd_msgport_thread,
				   THREAD_EXCEPTION_PORT, sigexc);
#elif defined (EXC_MASK_ALL)
  __thread_set_exception_ports (_hurd_msgport_thread,
				EXC_MASK_ALL & ~(EXC_MASK_SYSCALL
						 | EXC_MASK_MACH_SYSCALL
						 | EXC_MASK_RPC_ALERT),
				sigexc,
				EXCEPTION_STATE_IDENTITY,
				MACHINE_THREAD_STATE);
#else
# error thread_set_exception_ports?
#endif
  __mach_port_deallocate (__mach_task_self (), sigexc);
  assert_perror (err);
}
Example #14
0
/* Overlay TASK, executing FILE with arguments ARGV and environment ENVP.
   If TASK == mach_task_self (), some ports are dealloc'd by the exec server.
   ARGV and ENVP are terminated by NULL pointers.  */
error_t
_hurd_exec (task_t task, file_t file,
	    char *const argv[], char *const envp[])
{
  error_t err;
  char *args, *env;
  size_t argslen, envlen;
  int ints[INIT_INT_MAX];
  mach_port_t ports[_hurd_nports];
  struct hurd_userlink ulink_ports[_hurd_nports];
  file_t *dtable;
  unsigned int dtablesize, i;
  struct hurd_port **dtable_cells;
  struct hurd_userlink *ulink_dtable;
  struct hurd_sigstate *ss;
  mach_port_t *please_dealloc, *pdp;

  /* XXX needs to be hurdmalloc XXX */
  if (err = __argz_create (argv, &args, &argslen))
    return err;
  if (err = __argz_create (envp, &env, &envlen))
    goto outargs;

  /* Load up the ports to give to the new program.  */
  for (i = 0; i < _hurd_nports; ++i)
    if (i == INIT_PORT_PROC && task != __mach_task_self ())
      {
	/* This is another task, so we need to ask the proc server
	   for the right proc server port for it.  */
	if (err = __USEPORT (PROC, __proc_task2proc (port, task, &ports[i])))
	  {
	    while (--i > 0)
	      _hurd_port_free (&_hurd_ports[i], &ulink_ports[i], ports[i]);
	    goto outenv;
	  }
      }
    else
      ports[i] = _hurd_port_get (&_hurd_ports[i], &ulink_ports[i]);


  /* Load up the ints to give the new program.  */
  for (i = 0; i < INIT_INT_MAX; ++i)
    switch (i)
      {
      case INIT_UMASK:
	ints[i] = _hurd_umask;
	break;

      case INIT_SIGMASK:
      case INIT_SIGIGN:
      case INIT_SIGPENDING:
	/* We will set these all below.  */
	break;

      case INIT_TRACEMASK:
	ints[i] = _hurdsig_traced;
	break;

      default:
	ints[i] = 0;
      }

  ss = _hurd_self_sigstate ();

  assert (! __spin_lock_locked (&ss->critical_section_lock));
  __spin_lock (&ss->critical_section_lock);

  __spin_lock (&ss->lock);
  ints[INIT_SIGMASK] = ss->blocked;
  ints[INIT_SIGPENDING] = ss->pending;
  ints[INIT_SIGIGN] = 0;
  for (i = 1; i < NSIG; ++i)
    if (ss->actions[i].sa_handler == SIG_IGN)
      ints[INIT_SIGIGN] |= __sigmask (i);

  /* We hold the sigstate lock until the exec has failed so that no signal
     can arrive between when we pack the blocked and ignored signals, and
     when the exec actually happens.  A signal handler could change what
     signals are blocked and ignored.  Either the change will be reflected
     in the exec, or the signal will never be delivered.  Setting the
     critical section flag avoids anything we call trying to acquire the
     sigstate lock.  */

  __spin_unlock (&ss->lock);

  /* Pack up the descriptor table to give the new program.  */
  __mutex_lock (&_hurd_dtable_lock);

  dtablesize = _hurd_dtable ? _hurd_dtablesize : _hurd_init_dtablesize;

  if (task == __mach_task_self ())
    /* Request the exec server to deallocate some ports from us if the exec
       succeeds.  The init ports and descriptor ports will arrive in the
       new program's exec_startup message.  If we failed to deallocate
       them, the new program would have duplicate user references for them.
       But we cannot deallocate them ourselves, because we must still have
       them after a failed exec call.  */
    please_dealloc = __alloca ((_hurd_nports + (2 * dtablesize))
				* sizeof (mach_port_t));
  else
    please_dealloc = NULL;
  pdp = please_dealloc;

  if (_hurd_dtable != NULL)
    {
      dtable = __alloca (dtablesize * sizeof (dtable[0]));
      ulink_dtable = __alloca (dtablesize * sizeof (ulink_dtable[0]));
      dtable_cells = __alloca (dtablesize * sizeof (dtable_cells[0]));
      for (i = 0; i < dtablesize; ++i)
	{
	  struct hurd_fd *const d = _hurd_dtable[i];
	  if (d == NULL)
	    {
	      dtable[i] = MACH_PORT_NULL;
	      continue;
	    }
	  __spin_lock (&d->port.lock);
	  if (d->flags & FD_CLOEXEC)
	    {
	      /* This descriptor is marked to be closed on exec.
		 So don't pass it to the new program.  */
	      dtable[i] = MACH_PORT_NULL;
	      if (pdp && d->port.port != MACH_PORT_NULL)
		{
		  /* We still need to deallocate the ports.  */
		  *pdp++ = d->port.port;
		  if (d->ctty.port != MACH_PORT_NULL)
		    *pdp++ = d->ctty.port;
		}
	      __spin_unlock (&d->port.lock);
	    }
	  else
	    {
	      if (pdp && d->ctty.port != MACH_PORT_NULL)
		/* All the elements of DTABLE are added to PLEASE_DEALLOC
		   below, so we needn't add the port itself.
		   But we must deallocate the ctty port as well as
		   the normal port that got installed in DTABLE[I].  */
		*pdp++ = d->ctty.port;
	      dtable[i] = _hurd_port_locked_get (&d->port, &ulink_dtable[i]);
	      dtable_cells[i] = &d->port;
	    }
	}
    }
  else
    {
      dtable = _hurd_init_dtable;
      ulink_dtable = NULL;
      dtable_cells = NULL;
    }

  /* The information is all set up now.  Try to exec the file.  */

  {
    if (pdp)
      {
	/* Request the exec server to deallocate some ports from us if the exec
	   succeeds.  The init ports and descriptor ports will arrive in the
	   new program's exec_startup message.  If we failed to deallocate
	   them, the new program would have duplicate user references for them.
	   But we cannot deallocate them ourselves, because we must still have
	   them after a failed exec call.  */

	for (i = 0; i < _hurd_nports; ++i)
	  *pdp++ = ports[i];
	for (i = 0; i < dtablesize; ++i)
	  *pdp++ = dtable[i];
      }

    err = __file_exec (file, task, 0,
		       args, argslen, env, envlen,
		       dtable, MACH_MSG_TYPE_COPY_SEND, dtablesize,
		       ports, MACH_MSG_TYPE_COPY_SEND, _hurd_nports,
		       ints, INIT_INT_MAX,
		       please_dealloc, pdp - please_dealloc,
		       &_hurd_msgport, task == __mach_task_self () ? 1 : 0);
  }

  /* Release references to the standard ports.  */
  for (i = 0; i < _hurd_nports; ++i)
    if (i == INIT_PORT_PROC && task != __mach_task_self ())
      __mach_port_deallocate (__mach_task_self (), ports[i]);
    else
      _hurd_port_free (&_hurd_ports[i], &ulink_ports[i], ports[i]);

  if (ulink_dtable != NULL)
    /* Release references to the file descriptor ports.  */
    for (i = 0; i < dtablesize; ++i)
      if (dtable[i] != MACH_PORT_NULL)
	_hurd_port_free (dtable_cells[i], &ulink_dtable[i], dtable[i]);

  /* Release lock on the file descriptor table. */
  __mutex_unlock (&_hurd_dtable_lock);

  /* Safe to let signals happen now.  */
  _hurd_critical_section_unlock (ss);

 outargs:
  free (args);
 outenv:
  free (env);
  return err;
}