1 /* Copyright (C) 1992, 93, 94, 95, 96, 97, 99 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
14 You should have received a copy of the GNU Library General Public
15 License along with the GNU C Library; see the file COPYING.LIB. If not,
16 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA. */
20 #include <hurd/lookup.h>
24 #include "stdio-common/_itoa.h"
25 #include <hurd/term.h>
26 #include <hurd/paths.h>
29 /* Translate the error from dir_lookup into the error the user sees. */
31 lookup_error (error_t error
)
37 /* These indicate that the server does not understand dir_lookup
38 at all. If it were a directory, it would, by definition. */
46 __hurd_file_name_lookup (error_t (*use_init_port
)
47 (int which
, error_t (*operate
) (file_t
)),
48 file_t (*get_dtable_port
) (int fd
),
50 (file_t dir
, char *name
, int flags
, mode_t mode
,
51 retry_type
*do_retry
, string_t retry_name
,
53 const char *file_name
, int flags
, mode_t mode
,
57 enum retry_type doretry
;
58 char retryname
[1024]; /* XXX string_t LOSES! */
61 error_t
lookup_op (mach_port_t startdir
)
63 return lookup_error ((*lookup
) (startdir
, file_name
, flags
, mode
,
64 &doretry
, retryname
, result
));
68 lookup
= __dir_lookup
;
70 startport
= (file_name
[0] == '/') ? INIT_PORT_CRDIR
: INIT_PORT_CWDIR
;
71 while (file_name
[0] == '/')
74 if (flags
& O_NOFOLLOW
) /* See comments below about O_NOFOLLOW. */
77 if (flags
& O_DIRECTORY
)
79 /* The caller wants to require that the file we look up is a directory.
80 We can do this without an extra RPC by appending a trailing slash
81 to the file name we look up. */
82 size_t len
= strlen (file_name
);
85 else if (file_name
[len
- 1] != '/')
87 char *n
= alloca (len
+ 2);
88 memcpy (n
, file_name
, len
);
95 err
= (*use_init_port
) (startport
, &lookup_op
);
97 err
= __hurd_file_name_lookup_retry (use_init_port
, get_dtable_port
,
98 lookup
, doretry
, retryname
,
103 weak_alias (__hurd_file_name_lookup
, hurd_file_name_lookup
)
106 __hurd_file_name_lookup_retry (error_t (*use_init_port
)
107 (int which
, error_t (*operate
) (file_t
)),
108 file_t (*get_dtable_port
) (int fd
),
110 (file_t dir
, char *name
,
111 int flags
, mode_t mode
,
112 retry_type
*do_retry
, string_t retry_name
,
113 mach_port_t
*result
),
114 enum retry_type doretry
,
115 char retryname
[1024],
116 int flags
, mode_t mode
,
123 error_t
lookup_op (file_t startdir
)
125 while (file_name
[0] == '/')
128 return lookup_error ((*lookup
) (startdir
, file_name
, flags
, mode
,
129 &doretry
, retryname
, result
));
131 error_t
reauthenticate (file_t unauth
)
134 mach_port_t ref
= __mach_reply_port ();
135 error_t
reauth (auth_t auth
)
137 return __auth_user_authenticate (auth
, ref
,
138 MACH_MSG_TYPE_MAKE_SEND
,
141 err
= __io_reauthenticate (unauth
, ref
, MACH_MSG_TYPE_MAKE_SEND
);
143 err
= (*use_init_port
) (INIT_PORT_AUTH
, &reauth
);
144 __mach_port_destroy (__mach_task_self (), ref
);
145 __mach_port_deallocate (__mach_task_self (), unauth
);
150 lookup
= __dir_lookup
;
156 file_t startdir
= MACH_PORT_NULL
;
157 int dirport
= INIT_PORT_CWDIR
;
161 case FS_RETRY_REAUTH
:
162 if (err
= reauthenticate (*result
))
166 case FS_RETRY_NORMAL
:
168 if (nloops
++ >= SYMLOOP_MAX
)
172 /* An empty RETRYNAME indicates we have the final port. */
173 if (retryname
[0] == '\0' &&
174 /* If reauth'd, we must do one more retry on "" to give the new
175 translator a chance to make a new port for us. */
176 doretry
== FS_RETRY_NORMAL
)
178 if (flags
& O_NOFOLLOW
)
180 /* In Linux, O_NOFOLLOW means to reject symlinks. If we
181 did an O_NOLINK lookup above and io_stat here to check
182 for S_IFLNK, a translator like firmlink could easily
183 spoof this check by not showing S_IFLNK, but in fact
184 redirecting the lookup to some other name
185 (i.e. opening the very same holes a symlink would).
187 Instead we do an O_NOTRANS lookup above, and stat the
188 underlying node: if it has a translator set, and its
189 owner is not root (st_uid 0) then we reject it.
190 Since the motivation for this feature is security, and
191 that security presumes we trust the containing
192 directory, this check approximates the security of
193 refusing symlinks while accepting mount points.
194 Note that we actually permit something Linux doesn't:
195 we follow root-owned symlinks; if that is deemed
196 undesireable, we can add a final check for that
197 one exception to our general translator-based rule. */
199 err
= __io_stat (*result
, &st
);
201 && (st
.st_mode
& (S_IPTRANS
|S_IATRANS
)))
205 else if (st
.st_mode
& S_IPTRANS
)
209 size_t translen
= sizeof buf
;
210 err
= __file_get_translator (*result
,
213 && translen
> sizeof _HURD_SYMLINK
215 _HURD_SYMLINK
, sizeof _HURD_SYMLINK
))
221 /* We got a successful translation. Now apply any open-time
222 action flags we were passed. */
224 if (!err
&& (flags
& O_TRUNC
)) /* Asked to truncate the file. */
225 err
= __file_set_size (*result
, 0);
228 __mach_port_deallocate (__mach_task_self (), *result
);
233 file_name
= retryname
;
236 case FS_RETRY_MAGICAL
:
237 switch (retryname
[0])
240 dirport
= INIT_PORT_CRDIR
;
241 if (*result
!= MACH_PORT_NULL
)
242 __mach_port_deallocate (__mach_task_self (), *result
);
243 file_name
= &retryname
[1];
247 if (retryname
[1] == 'd' && retryname
[2] == '/')
253 fd
= (int) strtol (&retryname
[3], &end
, 10);
254 if (end
== NULL
|| errno
|| /* Malformed number. */
255 /* Check for excess text after the number. A slash
256 is valid; it ends the component. Anything else
257 does not name a numeric file descriptor. */
258 (*end
!= '/' && *end
!= '\0'))
263 if (! get_dtable_port
)
267 *result
= (*get_dtable_port
) (fd
);
268 if (*result
== MACH_PORT_NULL
)
270 /* If the name was a proper number, but the file
271 descriptor does not exist, we return EBADF instead
284 /* Do a normal retry on the remaining components. */
286 file_name
= end
+ 1; /* Skip the slash. */
295 if (retryname
[1] == 'a' && retryname
[2] == 'c' &&
296 retryname
[3] == 'h' && retryname
[4] == 't' &&
297 retryname
[5] == 'y' && retryname
[6] == 'p' &&
301 struct host_basic_info hostinfo
;
302 mach_msg_type_number_t hostinfocnt
= HOST_BASIC_INFO_COUNT
;
304 /* XXX want client's host */
305 if (err
= __host_info (__mach_host_self (), HOST_BASIC_INFO
,
306 (natural_t
*) &hostinfo
,
309 if (hostinfocnt
!= HOST_BASIC_INFO_COUNT
)
311 p
= _itoa (hostinfo
.cpu_subtype
, &retryname
[8], 10, 0);
313 p
= _itoa (hostinfo
.cpu_type
, &retryname
[8], 10, 0);
315 abort (); /* XXX write this right if this ever happens */
317 strcpy (retryname
, p
);
325 if (retryname
[1] == 't' && retryname
[2] == 'y')
326 switch (retryname
[3])
328 error_t
opentty (file_t
*result
)
331 error_t
ctty_open (file_t port
)
333 if (port
== MACH_PORT_NULL
)
334 return ENXIO
; /* No controlling terminal. */
335 return __termctty_open_terminal (port
,
339 err
= (*use_init_port
) (INIT_PORT_CTTYID
, &ctty_open
);
341 err
= reauthenticate (*result
);
346 return opentty (result
);
348 if (err
= opentty (&startdir
))
350 strcpy (retryname
, &retryname
[4]);
369 if (startdir
!= MACH_PORT_NULL
)
371 err
= lookup_op (startdir
);
372 __mach_port_deallocate (__mach_task_self (), startdir
);
373 startdir
= MACH_PORT_NULL
;
376 err
= (*use_init_port
) (dirport
, &lookup_op
);
381 weak_alias (__hurd_file_name_lookup_retry
, hurd_file_name_lookup_retry
)
384 __hurd_file_name_split (error_t (*use_init_port
)
385 (int which
, error_t (*operate
) (file_t
)),
386 file_t (*get_dtable_port
) (int fd
),
388 (file_t dir
, char *name
, int flags
, mode_t mode
,
389 retry_type
*do_retry
, string_t retry_name
,
390 mach_port_t
*result
),
391 const char *file_name
,
392 file_t
*dir
, char **name
)
394 error_t
addref (file_t crdir
)
397 return __mach_port_mod_refs (__mach_task_self (),
398 crdir
, MACH_PORT_RIGHT_SEND
, +1);
401 const char *lastslash
= strrchr (file_name
, '/');
403 if (lastslash
!= NULL
)
405 if (lastslash
== file_name
)
407 /* "/foobar" => crdir + "foobar". */
408 *name
= (char *) file_name
+ 1;
409 return (*use_init_port
) (INIT_PORT_CRDIR
, &addref
);
413 /* "/dir1/dir2/.../file". */
414 char dirname
[lastslash
- file_name
+ 1];
415 memcpy (dirname
, file_name
, lastslash
- file_name
);
416 dirname
[lastslash
- file_name
] = '\0';
417 *name
= (char *) lastslash
+ 1;
419 __hurd_file_name_lookup (use_init_port
, get_dtable_port
, lookup
,
425 /* "foobar" => cwdir + "foobar". */
426 *name
= (char *) file_name
;
427 return (*use_init_port
) (INIT_PORT_CWDIR
, &addref
);
430 weak_alias (__hurd_file_name_split
, hurd_file_name_split
)
434 __file_name_lookup (const char *file_name
, int flags
, mode_t mode
)
439 err
= __hurd_file_name_lookup (&_hurd_ports_use
, &__getdport
, 0,
440 file_name
, flags
, mode
& ~_hurd_umask
,
443 return err
? (__hurd_fail (err
), MACH_PORT_NULL
) : result
;
445 weak_alias (__file_name_lookup
, file_name_lookup
)
449 __file_name_split (const char *file_name
, char **name
)
454 err
= __hurd_file_name_split (&_hurd_ports_use
, &__getdport
, 0,
455 file_name
, &result
, name
);
457 return err
? (__hurd_fail (err
), MACH_PORT_NULL
) : result
;
459 weak_alias (__file_name_split
, file_name_split
)
463 __file_name_lookup_under (file_t startdir
,
464 const char *file_name
, int flags
, mode_t mode
)
469 error_t
use_init_port (int which
, error_t (*operate
) (mach_port_t
))
471 return (which
== INIT_PORT_CWDIR
? (*operate
) (startdir
) :
472 _hurd_ports_use (which
, operate
));
475 err
= __hurd_file_name_lookup (&use_init_port
, &__getdport
, 0,
476 file_name
, flags
, mode
& ~_hurd_umask
,
479 return err
? (__hurd_fail (err
), MACH_PORT_NULL
) : result
;
481 weak_alias (__file_name_lookup_under
, file_name_lookup_under
)