about summary refs log tree commit diff
path: root/sysdeps/mach/hurd/faccessat.c
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/mach/hurd/faccessat.c')
-rw-r--r--sysdeps/mach/hurd/faccessat.c181
1 files changed, 165 insertions, 16 deletions
diff --git a/sysdeps/mach/hurd/faccessat.c b/sysdeps/mach/hurd/faccessat.c
index 260060639f..d9bceaada7 100644
--- a/sysdeps/mach/hurd/faccessat.c
+++ b/sysdeps/mach/hurd/faccessat.c
@@ -23,31 +23,167 @@
 #include <sys/types.h>
 #include <hurd.h>
 #include <hurd/fd.h>
+#include <hurd/port.h>
+#include <hurd/id.h>
+#include <hurd/lookup.h>
 
-int
-faccessat (int fd, const char *file, int type, int flag)
+static int
+hurd_fail_seterrno (error_t err)
+{
+  return __hurd_fail (err);
+}
+
+static int
+hurd_fail_noerrno (error_t err)
+{
+  return -1;
+}
+
+static int
+__faccessat_common (int fd, const char *file, int type, int at_flags,
+                    int (*errfunc) (error_t))
 {
   error_t err;
-  file_t port;
-  int allowed, flags;
+  file_t rcrdir, rcwdir, io;
+  int flags, allowed;
 
-  if ((flag & AT_EACCESS) == 0)
+  if ((at_flags & AT_EACCESS) == AT_EACCESS)
     {
-      if (fd == AT_FDCWD || file[0] == '/')
-	return __access (file, type);
-      __set_errno (ENOTSUP);	/* XXX later */
-      return -1;
+      /* Use effective permissions.  */
+      io = __file_name_lookup_at (fd, at_flags &~ AT_EACCESS, file, 0, 0);
+      if (io == MACH_PORT_NULL)
+	return -1;
     }
+  else
+    {
+      /* We have to use real permissions instead of the
+         usual effective permissions.  */
+
+      int hurd_flags = 0;
+      __hurd_at_flags (&at_flags, &hurd_flags);
+
+      error_t reauthenticate_cwdir_at (file_t *result)
+	{
+	  /* Get a port to the FD directory, authenticated with the real IDs.  */
+	  error_t err;
+	  mach_port_t ref;
+	  ref = __mach_reply_port ();
+	  err = HURD_DPORT_USE
+	    (fd,
+	     ({
+	       err = __io_reauthenticate (port, ref, MACH_MSG_TYPE_MAKE_SEND);
+	       if (!err)
+		 err = __auth_user_authenticate (_hurd_id.rid_auth,
+						 ref, MACH_MSG_TYPE_MAKE_SEND,
+						 result);
+	       err;
+	     }));
+	  __mach_port_destroy (__mach_task_self (), ref);
+	  return err;
+	}
+
+      error_t reauthenticate (int which, file_t *result)
+	{
+	  /* Get a port to our root directory, authenticated with the real IDs.  */
+	  error_t err;
+	  mach_port_t ref;
+	  ref = __mach_reply_port ();
+	  err = HURD_PORT_USE
+	    (&_hurd_ports[which],
+	     ({
+	       err = __io_reauthenticate (port, ref, MACH_MSG_TYPE_MAKE_SEND);
+	       if (!err)
+		 err = __auth_user_authenticate (_hurd_id.rid_auth,
+						 ref, MACH_MSG_TYPE_MAKE_SEND,
+						 result);
+	       err;
+	     }));
+	  __mach_port_destroy (__mach_task_self (), ref);
+	  return err;
+	}
+
+      error_t init_port (int which, error_t (*operate) (mach_port_t))
+	{
+	  switch (which)
+	    {
+	    case INIT_PORT_AUTH:
+	      return (*operate) (_hurd_id.rid_auth);
+	    case INIT_PORT_CRDIR:
+	      return (reauthenticate (INIT_PORT_CRDIR, &rcrdir) ?:
+		      (*operate) (rcrdir));
+	    case INIT_PORT_CWDIR:
+	      if (fd == AT_FDCWD || file[0] == '/')
+		return (reauthenticate (INIT_PORT_CWDIR, &rcwdir) ?:
+			(*operate) (rcwdir));
+	      else
+		return (reauthenticate_cwdir_at (&rcwdir) ?:
+			(*operate) (rcwdir));
+	    default:
+	      return _hurd_ports_use (which, operate);
+	    }
+	}
+
+      rcrdir = rcwdir = MACH_PORT_NULL;
+
+      HURD_CRITICAL_BEGIN;
+
+      __mutex_lock (&_hurd_id.lock);
+      /* Get _hurd_id up to date.  */
+      if (err = _hurd_check_ids ())
+	goto lose;
 
-  port = __file_name_lookup_at (fd, flag &~ AT_EACCESS, file, 0, 0);
-  if (port == MACH_PORT_NULL)
-    return -1;
+      if (_hurd_id.rid_auth == MACH_PORT_NULL)
+	{
+	  /* Set up _hurd_id.rid_auth.  This is a special auth server port
+	     which uses the real uid and gid (the first aux uid and gid) as
+	     the only effective uid and gid.  */
+
+	  if (_hurd_id.aux.nuids < 1 || _hurd_id.aux.ngids < 1)
+	    {
+	      /* We do not have a real UID and GID.  Lose, lose, lose!  */
+	      err = EGRATUITOUS;
+	      goto lose;
+	    }
+
+	  /* Create a new auth port using our real UID and GID (the first
+	     auxiliary UID and GID) as the only effective IDs.  */
+	  if (err = __USEPORT (AUTH,
+			       __auth_makeauth (port,
+						NULL, MACH_MSG_TYPE_COPY_SEND, 0,
+						_hurd_id.aux.uids, 1,
+						_hurd_id.aux.uids,
+						_hurd_id.aux.nuids,
+						_hurd_id.aux.gids, 1,
+						_hurd_id.aux.gids,
+						_hurd_id.aux.ngids,
+						&_hurd_id.rid_auth)))
+	    goto lose;
+	}
+
+      if (!err)
+	/* Look up the file name using the modified init ports.  */
+	err = __hurd_file_name_lookup (&init_port, &__getdport, 0,
+				       file, hurd_flags, 0, &io);
+
+      /* We are done with _hurd_id.rid_auth now.  */
+     lose:
+      __mutex_unlock (&_hurd_id.lock);
+
+      HURD_CRITICAL_END;
+
+      if (rcrdir != MACH_PORT_NULL)
+	__mach_port_deallocate (__mach_task_self (), rcrdir);
+      if (rcwdir != MACH_PORT_NULL)
+	__mach_port_deallocate (__mach_task_self (), rcwdir);
+      if (err)
+	return errfunc (err);
+    }
 
   /* Find out what types of access we are allowed to this file.  */
-  err = __file_check_access (port, &allowed);
-  __mach_port_deallocate (__mach_task_self (), port);
+  err = __file_check_access (io, &allowed);
+  __mach_port_deallocate (__mach_task_self (), io);
   if (err)
-    return __hurd_fail (err);
+    return errfunc (err);
 
   flags = 0;
   if (type & R_OK)
@@ -59,7 +195,20 @@ faccessat (int fd, const char *file, int type, int flag)
 
   if (flags & ~allowed)
     /* We are not allowed all the requested types of access.  */
-    return __hurd_fail (EACCES);
+    return errfunc (EACCES);
 
   return 0;
 }
+
+int
+__faccessat_noerrno (int fd, const char *file, int type, int at_flags)
+{
+  return __faccessat_common (fd, file, type, at_flags, hurd_fail_noerrno);
+}
+
+int
+__faccessat (int fd, const char *file, int type, int at_flags)
+{
+  return __faccessat_common (fd, file, type, at_flags, hurd_fail_seterrno);
+}
+weak_alias (__faccessat, faccessat)