1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304
|
/*
* Copyright (C) 1987 - 1999 Free Software Foundation, Inc.
*
* This file is based on stuff from GNU Bash 1.14.7, the Bourne Again SHell.
* Everything that was changed is marked with the word `CHANGED'.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
Mon May 9 15:57:53 CDT 2005
did not update license info here because
(a) the original is still ok per GPL
(b) the original is lifted from another package and it's better to preserve
(c) this file is only used in swish-e binary, not libswish-e
*/
#include "sys.h"
#include "mem.h" /* swish-e memory */
#include <sys/stat.h>
#include "bash.h"
/* bash uses GID_T, autoconf defines GETGROUPS_T */
#define GID_T GETGROUPS_T
/*
* CHANGED:
* Perhaps these need new configure.in entries.
* The following macro's are used in bash, and below:
*/
#undef SHELL
#undef AFS
#undef NOGROUP
/*
* CHANGED:
* - Added prototypes,
* - used ANSI function arguments,
* - made all functions static and
* - changed all occurences of 'char *' into 'const char *' where possible.
* - exported functions needed in which.c
*/
static int group_member (GID_T gid);
static char *extract_colon_unit (const char *string, int *p_index);
/*===========================================================================
*
* Almost everything below is from execute_cmd.c from bash-1.14.7,
* a few functions are from other files: test.c, general.c and variables.c.
*
*/
#if defined (HAVE_GETGROUPS)
/* The number of groups that this user is a member of. */
static int ngroups = 0;
static GID_T *group_array = (GID_T *)NULL;
static int default_group_array_size = 0;
#endif /* HAVE_GETGROUPS */
#if !defined (NOGROUP)
# define NOGROUP (GID_T) -1
#endif
/* Return non-zero if GID is one that we have in our groups list. */
static int
group_member (GID_T gid)
{
static GID_T pgid = (GID_T)NOGROUP;
static GID_T egid = (GID_T)NOGROUP;
if (pgid == (GID_T)NOGROUP)
#if defined (SHELL)
pgid = (GID_T) current_user.gid;
#else /* !SHELL */
pgid = (GID_T) getgid ();
#endif /* !SHELL */
if (egid == (GID_T)NOGROUP)
#if defined (SHELL)
egid = (GID_T) current_user.egid;
#else /* !SHELL */
egid = (GID_T) getegid ();
#endif /* !SHELL */
if (gid == pgid || gid == egid)
return (1);
#if defined (HAVE_GETGROUPS)
/* getgroups () returns the number of elements that it was able to
place into the array. We simply continue to call getgroups ()
until the number of elements placed into the array is smaller than
the physical size of the array. */
while (ngroups == default_group_array_size)
{
default_group_array_size += 64;
group_array = (GID_T *)
xrealloc (group_array, default_group_array_size * sizeof (GID_T));
ngroups = getgroups (default_group_array_size, group_array);
}
/* In case of error, the user loses. */
if (ngroups < 0)
return (0);
/* Search through the list looking for GID. */
{
register int i;
for (i = 0; i < ngroups; i++)
if (gid == group_array[i])
return (1);
}
#endif /* HAVE_GETGROUPS */
return (0);
}
#define u_mode_bits(x) (((x) & 0000700) >> 6)
#define g_mode_bits(x) (((x) & 0000070) >> 3)
#define o_mode_bits(x) (((x) & 0000007) >> 0)
#define X_BIT(x) ((x) & 1)
/* Return some flags based on information about this file.
The EXISTS bit is non-zero if the file is found.
The EXECABLE bit is non-zero the file is executble.
Zero is returned if the file is not found. */
int
file_status (const char *name)
{
struct stat finfo;
static int user_id = -1;
/* Determine whether this file exists or not. */
if (stat (name, &finfo) < 0)
return (0);
/* If the file is a directory, then it is not "executable" in the
sense of the shell. */
if (S_ISDIR (finfo.st_mode))
return (FS_EXISTS);
#if defined (AFS)
/* We have to use access(2) to determine access because AFS does not
support Unix file system semantics. This may produce wrong
answers for non-AFS files when ruid != euid. I hate AFS. */
if (access (name, X_OK) == 0)
return (FS_EXISTS | FS_EXECABLE);
else
return (FS_EXISTS);
#else /* !AFS */
/* Find out if the file is actually executable. By definition, the
only other criteria is that the file has an execute bit set that
we can use. */
if (user_id == -1)
user_id = geteuid (); /* CHANGED: bash uses: current_user.euid; */
/* Root only requires execute permission for any of owner, group or
others to be able to exec a file. */
if (user_id == 0)
{
int bits;
bits = (u_mode_bits (finfo.st_mode) |
g_mode_bits (finfo.st_mode) |
o_mode_bits (finfo.st_mode));
if (X_BIT (bits))
return (FS_EXISTS | FS_EXECABLE);
}
/* If we are the owner of the file, the owner execute bit applies. */
if (user_id == finfo.st_uid )
return X_BIT (u_mode_bits (finfo.st_mode)) ? (FS_EXISTS | FS_EXECABLE) : FS_EXISTS;
/* If we are in the owning group, the group permissions apply. */
if (group_member (finfo.st_gid) )
return X_BIT (g_mode_bits (finfo.st_mode)) ? (FS_EXISTS | FS_EXECABLE) : FS_EXISTS;
/* If `others' have execute permission to the file, then so do we, since we are also `others'. */
return X_BIT (o_mode_bits (finfo.st_mode)) ? (FS_EXISTS | FS_EXECABLE) : FS_EXISTS;
#endif /* !AFS */
}
/* Return 1 if STRING is an absolute program name; it is absolute if it
contains any slashes. This is used to decide whether or not to look
up through $PATH. */
int
absolute_program (const char *string)
{
return ((char *)strchr (string, '/') != (char *)NULL);
}
/* Given a string containing units of information separated by colons,
return the next one pointed to by (P_INDEX), or NULL if there are no more.
Advance (P_INDEX) to the character after the colon. */
char *
extract_colon_unit (const char *string, int *p_index)
{
int i, start;
char path_separator;
#if defined( PATH_SEPARATOR )
path_separator = PATH_SEPARATOR[0];
#else
path_separator = ':';
#endif
i = *p_index;
if (!string || (i >= (int)strlen (string)))
return ((char *)NULL);
/* Each call to this routine leaves the index pointing at a colon if
there is more to the path. If I is > 0, then increment past the
`:'. If I is 0, then the path has a leading colon. Trailing colons
are handled OK by the `else' part of the if statement; an empty
string is returned in that case. */
if (i && string[i] == path_separator )
i++;
start = i;
while (string[i] && string[i] != path_separator ) i++;
*p_index = i;
if (i == start)
{
if (string[i])
(*p_index)++;
/* Return "" in the case of a trailing `:'. */
return (savestring (""));
}
else
{
char *value;
value = xmalloc (1 + i - start);
strncpy (value, string + start, i - start);
value [i - start] = '\0';
return (value);
}
}
/* Return the next element from PATH_LIST, a colon separated list of
paths. PATH_INDEX_POINTER is the address of an index into PATH_LIST;
the index is modified by this function.
Return the next element of PATH_LIST or NULL if there are no more. */
char *
get_next_path_element (const char *path_list, int *path_index_pointer)
{
char *path;
path = extract_colon_unit (path_list, path_index_pointer);
if (!path)
return (path);
if (!*path)
{
xfree (path);
path = savestring (".");
}
return (path);
}
/* Turn PATH, a directory, and NAME, a filename, into a full pathname.
This allocates new memory and returns it. */
char *
make_full_pathname (const char *path, const char *name, int name_len)
{
char *full_path;
int path_len;
path_len = strlen (path);
full_path = (char *) xmalloc (2 + path_len + name_len);
strcpy (full_path, path);
full_path[path_len] = '/';
strcpy (full_path + path_len + 1, name);
return (full_path);
}
|