1/* indir.c
2   See if a file is in a directory.
3
4   Copyright (C) 1992 Ian Lance Taylor
5
6   This file is part of the Taylor UUCP package.
7
8   This program is free software; you can redistribute it and/or
9   modify it under the terms of the GNU General Public License as
10   published by the Free Software Foundation; either version 2 of the
11   License, or (at your option) any later version.
12
13   This program is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16   General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program; if not, write to the Free Software
20   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
21
22   The author of the program may be contacted at ian@airs.com.
23   */
24
25#include "uucp.h"
26
27#include "uudefs.h"
28#include "sysdep.h"
29#include "system.h"
30
31#include <errno.h>
32
33/* See whether a file is in a directory, and optionally check access.  */
34
35boolean
36fsysdep_in_directory (zfile, zdir, fcheck, freadable, zuser)
37     const char *zfile;
38     const char *zdir;
39     boolean fcheck;
40     boolean freadable;
41     const char *zuser;
42{
43  size_t c;
44  char *zcopy, *zslash;
45  struct stat s;
46
47  if (*zfile != '/')
48    return FALSE;
49  c = strlen (zdir);
50  if (c > 0 && zdir[c - 1] == '/')
51    c--;
52  if (strncmp (zfile, zdir, c) != 0
53      || (zfile[c] != '/' && zfile[c] != '\0'))
54    return FALSE;
55  if (strstr (zfile + c, "/../") != NULL)
56    return FALSE;
57
58  /* If we're not checking access, get out now.  */
59  if (! fcheck)
60    return TRUE;
61
62  zcopy = zbufcpy (zfile);
63
64  /* Start checking directories after zdir.  Otherwise, we would
65     require that all directories down to /usr/spool/uucppublic be
66     publically searchable; they probably are but it should not be a
67     requirement.  */
68  zslash = zcopy + c;
69  do
70    {
71      char b;
72      struct stat shold;
73
74      b = *zslash;
75      *zslash = '\0';
76
77      shold = s;
78      if (stat (zcopy, &s) != 0)
79	{
80	  if (errno != ENOENT)
81	    {
82	      ulog (LOG_ERROR, "stat (%s): %s", zcopy, strerror (errno));
83	      ubuffree (zcopy);
84	      return FALSE;
85	    }
86
87	  /* If this is the top directory, any problems will be caught
88	     later when we try to open it.  */
89	  if (zslash == zcopy + c)
90	    {
91	      ubuffree (zcopy);
92	      return TRUE;
93	    }
94
95	  /* Go back and check the last directory for read or write
96	     access.  */
97	  s = shold;
98	  break;
99	}
100
101      /* If this is not a directory, get out of the loop.  */
102      if (! S_ISDIR (s.st_mode))
103	break;
104
105      /* Make sure the directory is searchable.  */
106      if (! fsuser_access (&s, X_OK, zuser))
107	{
108	  ulog (LOG_ERROR, "%s: %s", zcopy, strerror (EACCES));
109	  ubuffree (zcopy);
110	  return FALSE;
111	}
112
113      /* If we've reached the end of the string, get out.  */
114      if (b == '\0')
115	break;
116
117      *zslash = b;
118    }
119  while ((zslash = strchr (zslash + 1, '/')) != NULL);
120
121  /* At this point s holds a stat on the last component of the path.
122     We must check it for readability or writeability.  */
123  if (! fsuser_access (&s, freadable ? R_OK : W_OK, zuser))
124    {
125      ulog (LOG_ERROR, "%s: %s", zcopy, strerror (EACCES));
126      ubuffree (zcopy);
127      return FALSE;
128    }
129
130  ubuffree (zcopy);
131  return TRUE;
132}
133