summaryrefslogtreecommitdiff
path: root/pexpect/__init__.py
diff options
context:
space:
mode:
authorjquast <contact@jeffquast.com>2014-08-24 23:46:10 -0700
committerjquast <contact@jeffquast.com>2014-08-24 23:46:10 -0700
commit67e6c4ac018a0dabe50962beba537612cfb4fa22 (patch)
tree1188f80867cdf7c76447e92faec3c7391f8399ec /pexpect/__init__.py
parent8d96042177a6986ae5b117e31916638309b2fd03 (diff)
downloadpexpect-git-67e6c4ac018a0dabe50962beba537612cfb4fa22.tar.gz
Closes issue #104 -- cannot execute sudo(8)
Previously, misinterpreted that os.access(file, X_OK) always returns True on Solaris. Yes, but only for the uid of 0. Python issue #13706 closed "not a bug" reads to "just use os.stat()", so we went to great lengths to do so quite exhaustively. But this is wrong -- *only* when root, should we check the file modes -- os.access of X_OK works perfectly fine for non-root users. And, we should only check if any of the executable bits are set. Alas, it is true, you may execute that which you may not read -- because as root, you can always read it anyway. Verified similar solution in NetBSD test.c (/bin/test), OpenBSD ksh for its built-in test, and what FreeBSD/Darwin for their implementation of which.c.
Diffstat (limited to 'pexpect/__init__.py')
-rw-r--r--pexpect/__init__.py48
1 files changed, 16 insertions, 32 deletions
diff --git a/pexpect/__init__.py b/pexpect/__init__.py
index 4a34f15..57d8d91 100644
--- a/pexpect/__init__.py
+++ b/pexpect/__init__.py
@@ -2007,46 +2007,30 @@ class searcher_re(object):
def is_executable_file(path):
- """Checks that path is an executable regular file (or a symlink to a file).
-
- This is roughly ``os.path isfile(path) and os.access(path, os.X_OK)``, but
- on some platforms :func:`os.access` gives us the wrong answer, so this
- checks permission bits directly.
+ """Checks that path is an executable regular file, or a symlink to one.
+
+ This is roughly ``os.path isfile(path) and os.access(path, os.X_OK)``,
+ except for root users, which are permitted to execute a file only if
+ any of the execute bits are set.
"""
# follow symlinks,
fpath = os.path.realpath(path)
- # return False for non-files (directories, fifo, etc.)
if not os.path.isfile(fpath):
+ # non-files (directories, fifo, etc.)
return False
- # On Solaris, etc., "If the process has appropriate privileges, an
- # implementation may indicate success for X_OK even if none of the
- # execute file permission bits are set."
- #
- # For this reason, it is necessary to explicitly check st_mode
-
- # get file mode using os.stat, and check if `other',
- # that is anybody, may read and execute.
mode = os.stat(fpath).st_mode
- if mode & stat.S_IROTH and mode & stat.S_IXOTH:
- return True
-
- # get current user's group ids, and check if `group',
- # when matching ours, may read and execute.
- user_gids = os.getgroups() + [os.getgid()]
- if (os.stat(fpath).st_gid in user_gids and
- mode & stat.S_IRGRP and mode & stat.S_IXGRP):
- return True
-
- # finally, if file owner matches our effective userid,
- # check if `user', may read and execute.
- user_gids = os.getgroups() + [os.getgid()]
- if (os.stat(fpath).st_uid == os.geteuid() and
- mode & stat.S_IRUSR and mode & stat.S_IXUSR):
- return True
-
- return False
+
+ if os.getuid() == 0:
+ # when root, any permission bit of any section
+ # is fine, even if we do not own the file.
+ return bool(mode & (stat.S_IXUSR |
+ stat.S_IXGRP |
+ stat.S_IXOTH))
+
+ return os.access(fpath, os.X_OK)
+
def which(filename):
'''This takes a given filename; tries to find it in the environment path;