1 /* Copyright (C) 1992,93,94,95,96,97,99,2001 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
:
167 if (nloops
++ >= SYMLOOP_MAX
)
169 __mach_port_deallocate (__mach_task_self (), *result
);
173 /* An empty RETRYNAME indicates we have the final port. */
174 if (retryname
[0] == '\0' &&
175 /* If reauth'd, we must do one more retry on "" to give the new
176 translator a chance to make a new port for us. */
177 doretry
== FS_RETRY_NORMAL
)
179 if (flags
& O_NOFOLLOW
)
181 /* In Linux, O_NOFOLLOW means to reject symlinks. If we
182 did an O_NOLINK lookup above and io_stat here to check
183 for S_IFLNK, a translator like firmlink could easily
184 spoof this check by not showing S_IFLNK, but in fact
185 redirecting the lookup to some other name
186 (i.e. opening the very same holes a symlink would).
188 Instead we do an O_NOTRANS lookup above, and stat the
189 underlying node: if it has a translator set, and its
190 owner is not root (st_uid 0) then we reject it.
191 Since the motivation for this feature is security, and
192 that security presumes we trust the containing
193 directory, this check approximates the security of
194 refusing symlinks while accepting mount points.
195 Note that we actually permit something Linux doesn't:
196 we follow root-owned symlinks; if that is deemed
197 undesireable, we can add a final check for that
198 one exception to our general translator-based rule. */
200 err
= __io_stat (*result
, &st
);
202 && (st
.st_mode
& (S_IPTRANS
|S_IATRANS
)))
206 else if (st
.st_mode
& S_IPTRANS
)
210 size_t translen
= sizeof buf
;
211 err
= __file_get_translator (*result
,
214 && translen
> sizeof _HURD_SYMLINK
216 _HURD_SYMLINK
, sizeof _HURD_SYMLINK
))
222 /* We got a successful translation. Now apply any open-time
223 action flags we were passed. */
225 if (!err
&& (flags
& O_TRUNC
)) /* Asked to truncate the file. */
226 err
= __file_set_size (*result
, 0);
229 __mach_port_deallocate (__mach_task_self (), *result
);
234 file_name
= retryname
;
237 case FS_RETRY_MAGICAL
:
238 switch (retryname
[0])
241 dirport
= INIT_PORT_CRDIR
;
242 if (*result
!= MACH_PORT_NULL
)
243 __mach_port_deallocate (__mach_task_self (), *result
);
244 if (nloops
++ >= SYMLOOP_MAX
)
246 file_name
= &retryname
[1];
250 if (retryname
[1] == 'd' && retryname
[2] == '/')
256 fd
= (int) strtol (&retryname
[3], &end
, 10);
257 if (end
== NULL
|| errno
|| /* Malformed number. */
258 /* Check for excess text after the number. A slash
259 is valid; it ends the component. Anything else
260 does not name a numeric file descriptor. */
261 (*end
!= '/' && *end
!= '\0'))
266 if (! get_dtable_port
)
270 *result
= (*get_dtable_port
) (fd
);
271 if (*result
== MACH_PORT_NULL
)
273 /* If the name was a proper number, but the file
274 descriptor does not exist, we return EBADF instead
287 /* Do a normal retry on the remaining components. */
289 file_name
= end
+ 1; /* Skip the slash. */
298 if (retryname
[1] == 'a' && retryname
[2] == 'c' &&
299 retryname
[3] == 'h' && retryname
[4] == 't' &&
300 retryname
[5] == 'y' && retryname
[6] == 'p' &&
304 struct host_basic_info hostinfo
;
305 mach_msg_type_number_t hostinfocnt
= HOST_BASIC_INFO_COUNT
;
307 /* XXX want client's host */
308 if (err
= __host_info (__mach_host_self (), HOST_BASIC_INFO
,
309 (natural_t
*) &hostinfo
,
312 if (hostinfocnt
!= HOST_BASIC_INFO_COUNT
)
314 p
= _itoa (hostinfo
.cpu_subtype
, &retryname
[8], 10, 0);
316 p
= _itoa (hostinfo
.cpu_type
, &retryname
[8], 10, 0);
318 abort (); /* XXX write this right if this ever happens */
320 strcpy (retryname
, p
);
328 if (retryname
[1] == 't' && retryname
[2] == 'y')
329 switch (retryname
[3])
331 error_t
opentty (file_t
*result
)
334 error_t
ctty_open (file_t port
)
336 if (port
== MACH_PORT_NULL
)
337 return ENXIO
; /* No controlling terminal. */
338 return __termctty_open_terminal (port
,
342 err
= (*use_init_port
) (INIT_PORT_CTTYID
, &ctty_open
);
344 err
= reauthenticate (*result
);
349 return opentty (result
);
351 if (err
= opentty (&startdir
))
353 strcpy (retryname
, &retryname
[4]);
372 if (startdir
!= MACH_PORT_NULL
)
374 err
= lookup_op (startdir
);
375 __mach_port_deallocate (__mach_task_self (), startdir
);
376 startdir
= MACH_PORT_NULL
;
379 err
= (*use_init_port
) (dirport
, &lookup_op
);
384 weak_alias (__hurd_file_name_lookup_retry
, hurd_file_name_lookup_retry
)
387 __hurd_file_name_split (error_t (*use_init_port
)
388 (int which
, error_t (*operate
) (file_t
)),
389 file_t (*get_dtable_port
) (int fd
),
391 (file_t dir
, char *name
, int flags
, mode_t mode
,
392 retry_type
*do_retry
, string_t retry_name
,
393 mach_port_t
*result
),
394 const char *file_name
,
395 file_t
*dir
, char **name
)
397 error_t
addref (file_t crdir
)
400 return __mach_port_mod_refs (__mach_task_self (),
401 crdir
, MACH_PORT_RIGHT_SEND
, +1);
404 const char *lastslash
= strrchr (file_name
, '/');
406 if (lastslash
!= NULL
)
408 if (lastslash
== file_name
)
410 /* "/foobar" => crdir + "foobar". */
411 *name
= (char *) file_name
+ 1;
412 return (*use_init_port
) (INIT_PORT_CRDIR
, &addref
);
416 /* "/dir1/dir2/.../file". */
417 char dirname
[lastslash
- file_name
+ 1];
418 memcpy (dirname
, file_name
, lastslash
- file_name
);
419 dirname
[lastslash
- file_name
] = '\0';
420 *name
= (char *) lastslash
+ 1;
422 __hurd_file_name_lookup (use_init_port
, get_dtable_port
, lookup
,
428 /* "foobar" => cwdir + "foobar". */
429 *name
= (char *) file_name
;
430 return (*use_init_port
) (INIT_PORT_CWDIR
, &addref
);
433 weak_alias (__hurd_file_name_split
, hurd_file_name_split
)
435 /* This is the same as hurd_file_name_split, except that it ignores
436 trailing slashes (so *NAME is never ""). */
438 __hurd_directory_name_split (error_t (*use_init_port
)
439 (int which
, error_t (*operate
) (file_t
)),
440 file_t (*get_dtable_port
) (int fd
),
442 (file_t dir
, char *name
, int flags
, mode_t mode
,
443 retry_type
*do_retry
, string_t retry_name
,
444 mach_port_t
*result
),
445 const char *file_name
,
446 file_t
*dir
, char **name
)
448 error_t
addref (file_t crdir
)
451 return __mach_port_mod_refs (__mach_task_self (),
452 crdir
, MACH_PORT_RIGHT_SEND
, +1);
455 const char *lastslash
= strrchr (file_name
, '/');
457 if (lastslash
!= NULL
&& lastslash
[1] == '\0')
459 /* Trailing slash doesn't count. Look back further. */
461 /* Back up over all trailing slashes. */
462 while (lastslash
> file_name
&& *lastslash
== '/')
465 /* Find the last one earlier in the string, before the trailing ones. */
466 #if __GLIBC__ > 2 || __GLIBC_MINOR__ >= 2
467 lastslash
= __memrchr (file_name
, '/', lastslash
- file_name
);
469 /* Keep backing up, looking for a slash. */
471 if (lastslash
== file_name
)
473 /* Hit the start with no slash. */
477 while (*lastslash
-- != '/');
481 if (lastslash
!= NULL
)
483 if (lastslash
== file_name
)
485 /* "/foobar" => crdir + "foobar". */
486 *name
= (char *) file_name
+ 1;
487 return (*use_init_port
) (INIT_PORT_CRDIR
, &addref
);
491 /* "/dir1/dir2/.../file". */
492 char dirname
[lastslash
- file_name
+ 1];
493 memcpy (dirname
, file_name
, lastslash
- file_name
);
494 dirname
[lastslash
- file_name
] = '\0';
495 *name
= (char *) lastslash
+ 1;
497 __hurd_file_name_lookup (use_init_port
, get_dtable_port
, lookup
,
503 /* "foobar" => cwdir + "foobar". */
504 *name
= (char *) file_name
;
505 return (*use_init_port
) (INIT_PORT_CWDIR
, &addref
);
508 weak_alias (__hurd_directory_name_split
, hurd_directory_name_split
)
512 __file_name_lookup (const char *file_name
, int flags
, mode_t mode
)
517 err
= __hurd_file_name_lookup (&_hurd_ports_use
, &__getdport
, 0,
518 file_name
, flags
, mode
& ~_hurd_umask
,
521 return err
? (__hurd_fail (err
), MACH_PORT_NULL
) : result
;
523 weak_alias (__file_name_lookup
, file_name_lookup
)
527 __file_name_split (const char *file_name
, char **name
)
532 err
= __hurd_file_name_split (&_hurd_ports_use
, &__getdport
, 0,
533 file_name
, &result
, name
);
535 return err
? (__hurd_fail (err
), MACH_PORT_NULL
) : result
;
537 weak_alias (__file_name_split
, file_name_split
)
540 __directory_name_split (const char *directory_name
, char **name
)
545 err
= __hurd_directory_name_split (&_hurd_ports_use
, &__getdport
, 0,
546 directory_name
, &result
, name
);
548 return err
? (__hurd_fail (err
), MACH_PORT_NULL
) : result
;
550 weak_alias (__directory_name_split
, directory_name_split
)
554 __file_name_lookup_under (file_t startdir
,
555 const char *file_name
, int flags
, mode_t mode
)
560 error_t
use_init_port (int which
, error_t (*operate
) (mach_port_t
))
562 return (which
== INIT_PORT_CWDIR
? (*operate
) (startdir
) :
563 _hurd_ports_use (which
, operate
));
566 err
= __hurd_file_name_lookup (&use_init_port
, &__getdport
, 0,
567 file_name
, flags
, mode
& ~_hurd_umask
,
570 return err
? (__hurd_fail (err
), MACH_PORT_NULL
) : result
;
572 weak_alias (__file_name_lookup_under
, file_name_lookup_under
)