1 /* hairy bits of Hurd file name lookup
2 Copyright (C) 1992,1993,1994,1995,1996,1997,1999,2001,2002,2003
3 Free Software Foundation, Inc.
4 This file is part of the GNU C Library.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, write to the Free
18 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
22 #include <hurd/lookup.h>
23 #include <hurd/term.h>
24 #include <hurd/paths.h>
28 #include "stdio-common/_itoa.h"
30 /* Translate the error from dir_lookup into the error the user sees. */
32 lookup_error (error_t error
)
38 /* These indicate that the server does not understand dir_lookup
39 at all. If it were a directory, it would, by definition. */
47 __hurd_file_name_lookup_retry (error_t (*use_init_port
)
48 (int which
, error_t (*operate
) (file_t
)),
49 file_t (*get_dtable_port
) (int fd
),
51 (file_t dir
, char *name
,
52 int flags
, mode_t mode
,
53 retry_type
*do_retry
, string_t retry_name
,
55 enum retry_type doretry
,
57 int flags
, mode_t mode
,
64 error_t
lookup_op (file_t startdir
)
66 while (file_name
[0] == '/')
69 return lookup_error ((*lookup
) (startdir
, file_name
, flags
, mode
,
70 &doretry
, retryname
, result
));
72 error_t
reauthenticate (file_t unauth
)
75 mach_port_t ref
= __mach_reply_port ();
76 error_t
reauth (auth_t auth
)
78 return __auth_user_authenticate (auth
, ref
,
79 MACH_MSG_TYPE_MAKE_SEND
,
82 err
= __io_reauthenticate (unauth
, ref
, MACH_MSG_TYPE_MAKE_SEND
);
84 err
= (*use_init_port
) (INIT_PORT_AUTH
, &reauth
);
85 __mach_port_destroy (__mach_task_self (), ref
);
86 __mach_port_deallocate (__mach_task_self (), unauth
);
91 lookup
= __dir_lookup
;
97 file_t startdir
= MACH_PORT_NULL
;
98 int dirport
= INIT_PORT_CWDIR
;
102 case FS_RETRY_REAUTH
:
103 if (err
= reauthenticate (*result
))
107 case FS_RETRY_NORMAL
:
108 if (nloops
++ >= SYMLOOP_MAX
)
110 __mach_port_deallocate (__mach_task_self (), *result
);
114 /* An empty RETRYNAME indicates we have the final port. */
115 if (retryname
[0] == '\0' &&
116 /* If reauth'd, we must do one more retry on "" to give the new
117 translator a chance to make a new port for us. */
118 doretry
== FS_RETRY_NORMAL
)
120 if (flags
& O_NOFOLLOW
)
122 /* In Linux, O_NOFOLLOW means to reject symlinks. If we
123 did an O_NOLINK lookup above and io_stat here to check
124 for S_IFLNK, a translator like firmlink could easily
125 spoof this check by not showing S_IFLNK, but in fact
126 redirecting the lookup to some other name
127 (i.e. opening the very same holes a symlink would).
129 Instead we do an O_NOTRANS lookup above, and stat the
130 underlying node: if it has a translator set, and its
131 owner is not root (st_uid 0) then we reject it.
132 Since the motivation for this feature is security, and
133 that security presumes we trust the containing
134 directory, this check approximates the security of
135 refusing symlinks while accepting mount points.
136 Note that we actually permit something Linux doesn't:
137 we follow root-owned symlinks; if that is deemed
138 undesireable, we can add a final check for that
139 one exception to our general translator-based rule. */
141 err
= __io_stat (*result
, &st
);
143 && (st
.st_mode
& (S_IPTRANS
|S_IATRANS
)))
147 else if (st
.st_mode
& S_IPTRANS
)
151 size_t translen
= sizeof buf
;
152 err
= __file_get_translator (*result
,
155 && translen
> sizeof _HURD_SYMLINK
157 _HURD_SYMLINK
, sizeof _HURD_SYMLINK
))
163 /* We got a successful translation. Now apply any open-time
164 action flags we were passed. */
166 if (!err
&& (flags
& O_TRUNC
)) /* Asked to truncate the file. */
167 err
= __file_set_size (*result
, 0);
170 __mach_port_deallocate (__mach_task_self (), *result
);
175 file_name
= retryname
;
178 case FS_RETRY_MAGICAL
:
179 switch (retryname
[0])
182 dirport
= INIT_PORT_CRDIR
;
183 if (*result
!= MACH_PORT_NULL
)
184 __mach_port_deallocate (__mach_task_self (), *result
);
185 if (nloops
++ >= SYMLOOP_MAX
)
187 file_name
= &retryname
[1];
191 if (retryname
[1] == 'd' && retryname
[2] == '/')
197 fd
= (int) strtoul (&retryname
[3], &end
, 10);
198 if (end
== NULL
|| errno
|| /* Malformed number. */
199 /* Check for excess text after the number. A slash
200 is valid; it ends the component. Anything else
201 does not name a numeric file descriptor. */
202 (*end
!= '/' && *end
!= '\0'))
207 if (! get_dtable_port
)
211 *result
= (*get_dtable_port
) (fd
);
212 if (*result
== MACH_PORT_NULL
)
214 /* If the name was a proper number, but the file
215 descriptor does not exist, we return EBADF instead
228 /* Do a normal retry on the remaining components. */
230 file_name
= end
+ 1; /* Skip the slash. */
239 if (retryname
[1] == 'a' && retryname
[2] == 'c' &&
240 retryname
[3] == 'h' && retryname
[4] == 't' &&
241 retryname
[5] == 'y' && retryname
[6] == 'p' &&
245 struct host_basic_info hostinfo
;
246 mach_msg_type_number_t hostinfocnt
= HOST_BASIC_INFO_COUNT
;
248 /* XXX want client's host */
249 if (err
= __host_info (__mach_host_self (), HOST_BASIC_INFO
,
250 (natural_t
*) &hostinfo
,
253 if (hostinfocnt
!= HOST_BASIC_INFO_COUNT
)
255 p
= _itoa (hostinfo
.cpu_subtype
, &retryname
[8], 10, 0);
257 p
= _itoa (hostinfo
.cpu_type
, &retryname
[8], 10, 0);
259 abort (); /* XXX write this right if this ever happens */
261 strcpy (retryname
, p
);
269 if (retryname
[1] == 't' && retryname
[2] == 'y')
270 switch (retryname
[3])
272 error_t
opentty (file_t
*result
)
275 error_t
ctty_open (file_t port
)
277 if (port
== MACH_PORT_NULL
)
278 return ENXIO
; /* No controlling terminal. */
279 return __termctty_open_terminal (port
,
283 err
= (*use_init_port
) (INIT_PORT_CTTYID
, &ctty_open
);
285 err
= reauthenticate (*result
);
290 return opentty (result
);
292 if (err
= opentty (&startdir
))
294 strcpy (retryname
, &retryname
[4]);
313 if (startdir
!= MACH_PORT_NULL
)
315 err
= lookup_op (startdir
);
316 __mach_port_deallocate (__mach_task_self (), startdir
);
317 startdir
= MACH_PORT_NULL
;
320 err
= (*use_init_port
) (dirport
, &lookup_op
);
325 weak_alias (__hurd_file_name_lookup_retry
, hurd_file_name_lookup_retry
)