1/* uacces.c
2   Check access to a file by user name.
3
4   Copyright (C) 1992, 2002 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
30#include <pwd.h>
31#include <errno.h>
32
33#if HAVE_GETGRENT
34#include <grp.h>
35#if GETGRENT_DECLARATION_OK
36#ifndef getgrent
37extern struct group *getgrent ();
38#endif
39#endif
40#endif /* HAVE_GETGRENT */
41
42#if GETPWNAM_DECLARATION_OK
43#ifndef getpwnam
44extern struct passwd *getpwnam ();
45#endif
46#endif
47
48/* Do access(2) on a stat structure, except that the user name is
49   provided.  If the user name in zuser is NULL, require the file to
50   be accessible to the world.  Return TRUE if access is permitted,
51   FALSE otherwise.  This does not log an error message.  */
52
53boolean
54fsuser_access (q, imode, zuser)
55     const struct stat *q;
56     int imode;
57     const char *zuser;
58{
59  static char *zuser_hold;
60  static uid_t iuid_hold;
61  static gid_t igid_hold;
62  static int cgroups_hold;
63  static gid_t *paigroups_hold;
64  unsigned int ir, iw, ix, iand;
65
66  if (imode == F_OK)
67    return TRUE;
68
69  if (zuser != NULL)
70    {
71      /* We keep static variables around for the last user we did, to
72	 avoid looking up a user multiple times.  */
73      if (zuser_hold == NULL || strcmp (zuser_hold, zuser) != 0)
74	{
75	  struct passwd *qpwd;
76
77	  if (zuser_hold != NULL)
78	    {
79	      ubuffree (zuser_hold);
80	      zuser_hold = NULL;
81	      cgroups_hold = 0;
82	      xfree ((pointer) paigroups_hold);
83	      paigroups_hold = NULL;
84	    }
85
86	  qpwd = getpwnam ((char *) zuser);
87	  if (qpwd == NULL)
88	    {
89	      /* Check this as a remote request.  */
90	      zuser = NULL;
91	    }
92	  else
93	    {
94#if HAVE_GETGRENT
95	      struct group *qg;
96#endif
97
98	      zuser_hold = zbufcpy (zuser);
99
100	      iuid_hold = qpwd->pw_uid;
101	      igid_hold = qpwd->pw_gid;
102
103#if HAVE_GETGRENT
104	      /* Get the list of groups for this user.  This is
105		 definitely more appropriate for BSD than for System
106		 V.  It may just be a waste of time, and perhaps it
107		 should be configurable.  */
108	      setgrent ();
109	      while ((qg = getgrent ()) != NULL)
110		{
111		  const char **pz;
112
113		  if (qg->gr_gid == igid_hold)
114		    continue;
115		  for (pz = (const char **) qg->gr_mem; *pz != NULL; pz++)
116		    {
117		      if ((*pz)[0] == *zuser
118			  && strcmp (*pz, zuser) == 0)
119			{
120			  paigroups_hold = ((gid_t *)
121					    (xrealloc
122					     ((pointer) paigroups_hold,
123					      ((cgroups_hold + 1)
124					       * sizeof (gid_t)))));
125			  paigroups_hold[cgroups_hold] = qg->gr_gid;
126			  ++cgroups_hold;
127			  break;
128			}
129		    }
130		}
131	      endgrent ();
132#endif
133	    }
134	}
135    }
136
137
138  /* Now do the actual access check.  */
139
140  if (zuser != NULL)
141    {
142      /* The superuser can do anything.  */
143      if (iuid_hold == 0)
144	return TRUE;
145
146      /* If this is the uid we're running under, there's no point to
147	 checking access further, because when we actually try the
148	 operation the system will do the checking for us.  */
149      if (iuid_hold == geteuid ())
150	return TRUE;
151    }
152
153  ir = S_IROTH;
154  iw = S_IWOTH;
155  ix = S_IXOTH;
156
157  if (zuser != NULL)
158    {
159      if (iuid_hold == q->st_uid)
160	{
161	  ir = S_IRUSR;
162	  iw = S_IWUSR;
163	  ix = S_IXUSR;
164	}
165      else
166	{
167	  boolean fgroup;
168
169	  fgroup = FALSE;
170	  if (igid_hold == q->st_gid)
171	    fgroup = TRUE;
172	  else
173	    {
174	      int i;
175
176	      for (i = 0; i < cgroups_hold; i++)
177		{
178		  if (paigroups_hold[i] == q->st_gid)
179		    {
180		      fgroup = TRUE;
181		      break;
182		    }
183		}
184	    }
185
186	  if (fgroup)
187	    {
188	      ir = S_IRGRP;
189	      iw = S_IWGRP;
190	      ix = S_IXGRP;
191	    }
192	}
193    }
194
195  iand = 0;
196  if ((imode & R_OK) != 0)
197    iand |= ir;
198  if ((imode & W_OK) != 0)
199    iand |= iw;
200  if ((imode & X_OK) != 0)
201    iand |= ix;
202
203  return (q->st_mode & iand) == iand;
204}
205