1 /* Test for access to file, relative to open directory.  Hurd version.
2    Copyright (C) 2006-2021 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4 
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9 
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14 
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <https://www.gnu.org/licenses/>.  */
18 
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <stddef.h>
22 #include <unistd.h>
23 #include <sys/types.h>
24 #include <hurd.h>
25 #include <hurd/fd.h>
26 #include <hurd/port.h>
27 #include <hurd/id.h>
28 #include <hurd/lookup.h>
29 
30 static int
hurd_fail_seterrno(error_t err)31 hurd_fail_seterrno (error_t err)
32 {
33   return __hurd_fail (err);
34 }
35 
36 static int
hurd_fail_noerrno(error_t err)37 hurd_fail_noerrno (error_t err)
38 {
39   return -1;
40 }
41 
42 static int
__faccessat_common(int fd,const char * file,int type,int at_flags,int (* errfunc)(error_t))43 __faccessat_common (int fd, const char *file, int type, int at_flags,
44                     int (*errfunc) (error_t))
45 {
46   error_t err;
47   file_t rcrdir, rcwdir, io;
48   int flags, allowed;
49 
50   if ((at_flags & AT_EACCESS) == AT_EACCESS)
51     {
52       /* Use effective permissions.  */
53       io = __file_name_lookup_at (fd, at_flags &~ AT_EACCESS, file, 0, 0);
54       if (io == MACH_PORT_NULL)
55 	return -1;
56     }
57   else
58     {
59       /* We have to use real permissions instead of the
60          usual effective permissions.  */
61 
62       int hurd_flags = 0;
63       err = __hurd_at_flags (&at_flags, &hurd_flags);
64       if (err)
65 	return errfunc (err);
66 
67       error_t reauthenticate_cwdir_at (file_t *result)
68 	{
69 	  /* Get a port to the FD directory, authenticated with the real IDs.  */
70 	  error_t err;
71 	  mach_port_t ref;
72 	  ref = __mach_reply_port ();
73 	  err = HURD_DPORT_USE
74 	    (fd,
75 	     ({
76 	       err = __io_reauthenticate (port, ref, MACH_MSG_TYPE_MAKE_SEND);
77 	       if (!err)
78 		 err = __auth_user_authenticate (_hurd_id.rid_auth,
79 						 ref, MACH_MSG_TYPE_MAKE_SEND,
80 						 result);
81 	       err;
82 	     }));
83 	  __mach_port_destroy (__mach_task_self (), ref);
84 	  return err;
85 	}
86 
87       error_t reauthenticate (int which, file_t *result)
88 	{
89 	  /* Get a port to our root directory, authenticated with the real IDs.  */
90 	  error_t err;
91 	  mach_port_t ref;
92 	  ref = __mach_reply_port ();
93 	  err = HURD_PORT_USE
94 	    (&_hurd_ports[which],
95 	     ({
96 	       err = __io_reauthenticate (port, ref, MACH_MSG_TYPE_MAKE_SEND);
97 	       if (!err)
98 		 err = __auth_user_authenticate (_hurd_id.rid_auth,
99 						 ref, MACH_MSG_TYPE_MAKE_SEND,
100 						 result);
101 	       err;
102 	     }));
103 	  __mach_port_destroy (__mach_task_self (), ref);
104 	  return err;
105 	}
106 
107       error_t init_port (int which, error_t (*operate) (mach_port_t))
108 	{
109 	  switch (which)
110 	    {
111 	    case INIT_PORT_AUTH:
112 	      return (*operate) (_hurd_id.rid_auth);
113 	    case INIT_PORT_CRDIR:
114 	      return (reauthenticate (INIT_PORT_CRDIR, &rcrdir) ?:
115 		      (*operate) (rcrdir));
116 	    case INIT_PORT_CWDIR:
117 	      if (fd == AT_FDCWD || file[0] == '/')
118 		return (reauthenticate (INIT_PORT_CWDIR, &rcwdir) ?:
119 			(*operate) (rcwdir));
120 	      else
121 		return (reauthenticate_cwdir_at (&rcwdir) ?:
122 			(*operate) (rcwdir));
123 	    default:
124 	      return _hurd_ports_use (which, operate);
125 	    }
126 	}
127 
128       rcrdir = rcwdir = MACH_PORT_NULL;
129 
130      retry:
131       HURD_CRITICAL_BEGIN;
132 
133       __mutex_lock (&_hurd_id.lock);
134       /* Get _hurd_id up to date.  */
135       if (err = _hurd_check_ids ())
136 	goto lose;
137 
138       if (_hurd_id.rid_auth == MACH_PORT_NULL)
139 	{
140 	  /* Set up _hurd_id.rid_auth.  This is a special auth server port
141 	     which uses the real uid and gid (the first aux uid and gid) as
142 	     the only effective uid and gid.  */
143 
144 	  if (_hurd_id.aux.nuids < 1 || _hurd_id.aux.ngids < 1)
145 	    {
146 	      /* We do not have a real UID and GID.  Lose, lose, lose!  */
147 	      err = EGRATUITOUS;
148 	      goto lose;
149 	    }
150 
151 	  /* Create a new auth port using our real UID and GID (the first
152 	     auxiliary UID and GID) as the only effective IDs.  */
153 	  if (err = __USEPORT (AUTH,
154 			       __auth_makeauth (port,
155 						NULL, MACH_MSG_TYPE_COPY_SEND, 0,
156 						_hurd_id.aux.uids, 1,
157 						_hurd_id.aux.uids,
158 						_hurd_id.aux.nuids,
159 						_hurd_id.aux.gids, 1,
160 						_hurd_id.aux.gids,
161 						_hurd_id.aux.ngids,
162 						&_hurd_id.rid_auth)))
163 	    goto lose;
164 	}
165 
166       if (!err)
167 	/* Look up the file name using the modified init ports.  */
168 	err = __hurd_file_name_lookup (&init_port, &__getdport, 0,
169 				       file, hurd_flags, 0, &io);
170 
171       /* We are done with _hurd_id.rid_auth now.  */
172      lose:
173       __mutex_unlock (&_hurd_id.lock);
174 
175       HURD_CRITICAL_END;
176       if (err == EINTR)
177 	/* Got a signal while inside an RPC of the critical section, retry again */
178 	goto retry;
179 
180       if (rcrdir != MACH_PORT_NULL)
181 	__mach_port_deallocate (__mach_task_self (), rcrdir);
182       if (rcwdir != MACH_PORT_NULL)
183 	__mach_port_deallocate (__mach_task_self (), rcwdir);
184       if (err)
185 	return errfunc (err);
186     }
187 
188   /* Find out what types of access we are allowed to this file.  */
189   err = __file_check_access (io, &allowed);
190   __mach_port_deallocate (__mach_task_self (), io);
191   if (err)
192     return errfunc (err);
193 
194   flags = 0;
195   if (type & R_OK)
196     flags |= O_READ;
197   if (type & W_OK)
198     flags |= O_WRITE;
199   if (type & X_OK)
200     flags |= O_EXEC;
201 
202   if (flags & ~allowed)
203     /* We are not allowed all the requested types of access.  */
204     return errfunc (EACCES);
205 
206   return 0;
207 }
208 
209 int
__faccessat_noerrno(int fd,const char * file,int type,int at_flags)210 __faccessat_noerrno (int fd, const char *file, int type, int at_flags)
211 {
212   return __faccessat_common (fd, file, type, at_flags, hurd_fail_noerrno);
213 }
214 
215 int
__faccessat(int fd,const char * file,int type,int at_flags)216 __faccessat (int fd, const char *file, int type, int at_flags)
217 {
218   return __faccessat_common (fd, file, type, at_flags, hurd_fail_seterrno);
219 }
220 weak_alias (__faccessat, faccessat)
221