locales/mag_IN: Fix syntax error
[glibc.git] / hurd / lookup-retry.c
blob4fa2a2199c402219473af5a5ccfe1f19ef20b365
1 /* hairy bits of Hurd file name lookup
2 Copyright (C) 1992-2012 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
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.
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.
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 <http://www.gnu.org/licenses/>. */
19 #include <hurd.h>
20 #include <hurd/lookup.h>
21 #include <hurd/term.h>
22 #include <hurd/paths.h>
23 #include <limits.h>
24 #include <fcntl.h>
25 #include <string.h>
26 #include <_itoa.h>
28 /* Translate the error from dir_lookup into the error the user sees. */
29 static inline error_t
30 lookup_error (error_t error)
32 switch (error)
34 case EOPNOTSUPP:
35 case MIG_BAD_ID:
36 /* These indicate that the server does not understand dir_lookup
37 at all. If it were a directory, it would, by definition. */
38 return ENOTDIR;
39 default:
40 return error;
44 error_t
45 __hurd_file_name_lookup_retry (error_t (*use_init_port)
46 (int which, error_t (*operate) (file_t)),
47 file_t (*get_dtable_port) (int fd),
48 error_t (*lookup)
49 (file_t dir, char *name,
50 int flags, mode_t mode,
51 retry_type *do_retry, string_t retry_name,
52 mach_port_t *result),
53 enum retry_type doretry,
54 char retryname[1024],
55 int flags, mode_t mode,
56 file_t *result)
58 error_t err;
59 char *file_name;
60 int nloops;
62 error_t lookup_op (file_t startdir)
64 while (file_name[0] == '/')
65 file_name++;
67 return lookup_error ((*lookup) (startdir, file_name, flags, mode,
68 &doretry, retryname, result));
70 error_t reauthenticate (file_t unauth)
72 error_t err;
73 mach_port_t ref = __mach_reply_port ();
74 error_t reauth (auth_t auth)
76 return __auth_user_authenticate (auth, ref,
77 MACH_MSG_TYPE_MAKE_SEND,
78 result);
80 err = __io_reauthenticate (unauth, ref, MACH_MSG_TYPE_MAKE_SEND);
81 if (! err)
82 err = (*use_init_port) (INIT_PORT_AUTH, &reauth);
83 __mach_port_destroy (__mach_task_self (), ref);
84 __mach_port_deallocate (__mach_task_self (), unauth);
85 return err;
88 if (! lookup)
89 lookup = __dir_lookup;
91 nloops = 0;
92 err = 0;
95 file_t startdir = MACH_PORT_NULL;
96 int dirport = INIT_PORT_CWDIR;
98 switch (doretry)
100 case FS_RETRY_REAUTH:
101 if (err = reauthenticate (*result))
102 return err;
103 /* Fall through. */
105 case FS_RETRY_NORMAL:
106 if (nloops++ >= SYMLOOP_MAX)
108 __mach_port_deallocate (__mach_task_self (), *result);
109 return ELOOP;
112 /* An empty RETRYNAME indicates we have the final port. */
113 if (retryname[0] == '\0' &&
114 /* If reauth'd, we must do one more retry on "" to give the new
115 translator a chance to make a new port for us. */
116 doretry == FS_RETRY_NORMAL)
118 if (flags & O_NOFOLLOW)
120 /* In Linux, O_NOFOLLOW means to reject symlinks. If we
121 did an O_NOLINK lookup above and io_stat here to check
122 for S_IFLNK, a translator like firmlink could easily
123 spoof this check by not showing S_IFLNK, but in fact
124 redirecting the lookup to some other name
125 (i.e. opening the very same holes a symlink would).
127 Instead we do an O_NOTRANS lookup above, and stat the
128 underlying node: if it has a translator set, and its
129 owner is not root (st_uid 0) then we reject it.
130 Since the motivation for this feature is security, and
131 that security presumes we trust the containing
132 directory, this check approximates the security of
133 refusing symlinks while accepting mount points.
134 Note that we actually permit something Linux doesn't:
135 we follow root-owned symlinks; if that is deemed
136 undesireable, we can add a final check for that
137 one exception to our general translator-based rule. */
138 struct stat64 st;
139 err = __io_stat (*result, &st);
140 if (!err
141 && (st.st_mode & (S_IPTRANS|S_IATRANS)))
143 if (st.st_uid != 0)
144 err = ENOENT;
145 else if (st.st_mode & S_IPTRANS)
147 char buf[1024];
148 char *trans = buf;
149 size_t translen = sizeof buf;
150 err = __file_get_translator (*result,
151 &trans, &translen);
152 if (!err
153 && translen > sizeof _HURD_SYMLINK
154 && !memcmp (trans,
155 _HURD_SYMLINK, sizeof _HURD_SYMLINK))
156 err = ENOENT;
161 /* We got a successful translation. Now apply any open-time
162 action flags we were passed. */
164 if (!err && (flags & O_TRUNC)) /* Asked to truncate the file. */
165 err = __file_set_size (*result, 0);
167 if (err)
168 __mach_port_deallocate (__mach_task_self (), *result);
169 return err;
172 startdir = *result;
173 file_name = retryname;
174 break;
176 case FS_RETRY_MAGICAL:
177 switch (retryname[0])
179 case '/':
180 dirport = INIT_PORT_CRDIR;
181 if (*result != MACH_PORT_NULL)
182 __mach_port_deallocate (__mach_task_self (), *result);
183 if (nloops++ >= SYMLOOP_MAX)
184 return ELOOP;
185 file_name = &retryname[1];
186 break;
188 case 'f':
189 if (retryname[1] == 'd' && retryname[2] == '/')
191 int fd;
192 char *end;
193 int save = errno;
194 errno = 0;
195 fd = (int) __strtoul_internal (&retryname[3], &end, 10, 0);
196 if (end == NULL || errno || /* Malformed number. */
197 /* Check for excess text after the number. A slash
198 is valid; it ends the component. Anything else
199 does not name a numeric file descriptor. */
200 (*end != '/' && *end != '\0'))
202 errno = save;
203 return ENOENT;
205 if (! get_dtable_port)
206 err = EGRATUITOUS;
207 else
209 *result = (*get_dtable_port) (fd);
210 if (*result == MACH_PORT_NULL)
212 /* If the name was a proper number, but the file
213 descriptor does not exist, we return EBADF instead
214 of ENOENT. */
215 err = errno;
216 errno = save;
219 errno = save;
220 if (err)
221 return err;
222 if (*end == '\0')
223 return 0;
224 else
226 /* Do a normal retry on the remaining components. */
227 startdir = *result;
228 file_name = end + 1; /* Skip the slash. */
229 break;
232 else
233 goto bad_magic;
234 break;
236 case 'm':
237 if (retryname[1] == 'a' && retryname[2] == 'c' &&
238 retryname[3] == 'h' && retryname[4] == 't' &&
239 retryname[5] == 'y' && retryname[6] == 'p' &&
240 retryname[7] == 'e')
242 error_t err;
243 struct host_basic_info hostinfo;
244 mach_msg_type_number_t hostinfocnt = HOST_BASIC_INFO_COUNT;
245 char *p;
246 /* XXX want client's host */
247 if (err = __host_info (__mach_host_self (), HOST_BASIC_INFO,
248 (integer_t *) &hostinfo,
249 &hostinfocnt))
250 return err;
251 if (hostinfocnt != HOST_BASIC_INFO_COUNT)
252 return EGRATUITOUS;
253 p = _itoa (hostinfo.cpu_subtype, &retryname[8], 10, 0);
254 *--p = '/';
255 p = _itoa (hostinfo.cpu_type, &retryname[8], 10, 0);
256 if (p < retryname)
257 abort (); /* XXX write this right if this ever happens */
258 if (p > retryname)
259 strcpy (retryname, p);
260 startdir = *result;
262 else
263 goto bad_magic;
264 break;
266 case 't':
267 if (retryname[1] == 't' && retryname[2] == 'y')
268 switch (retryname[3])
270 error_t opentty (file_t *result)
272 error_t err;
273 error_t ctty_open (file_t port)
275 if (port == MACH_PORT_NULL)
276 return ENXIO; /* No controlling terminal. */
277 return __termctty_open_terminal (port,
278 flags,
279 result);
281 err = (*use_init_port) (INIT_PORT_CTTYID, &ctty_open);
282 if (! err)
283 err = reauthenticate (*result);
284 return err;
287 case '\0':
288 return opentty (result);
289 case '/':
290 if (err = opentty (&startdir))
291 return err;
292 strcpy (retryname, &retryname[4]);
293 break;
294 default:
295 goto bad_magic;
297 else
298 goto bad_magic;
299 break;
301 default:
302 bad_magic:
303 return EGRATUITOUS;
305 break;
307 default:
308 return EGRATUITOUS;
311 if (startdir != MACH_PORT_NULL)
313 err = lookup_op (startdir);
314 __mach_port_deallocate (__mach_task_self (), startdir);
315 startdir = MACH_PORT_NULL;
317 else
318 err = (*use_init_port) (dirport, &lookup_op);
319 } while (! err);
321 return err;
323 weak_alias (__hurd_file_name_lookup_retry, hurd_file_name_lookup_retry)