diff options
-rw-r--r-- | ChangeLog.txt | 3 | ||||
-rw-r--r-- | guts/execv.c | 4 | ||||
-rw-r--r-- | guts/execve.c | 4 | ||||
-rw-r--r-- | guts/execvp.c | 4 | ||||
-rw-r--r-- | pseudo_client.c | 145 | ||||
-rw-r--r-- | pseudo_client.h | 1 | ||||
-rw-r--r-- | pseudo_util.c | 6 |
7 files changed, 160 insertions, 7 deletions
diff --git a/ChangeLog.txt b/ChangeLog.txt index 6850e42..aea94d3 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,3 +1,6 @@ +2011-02-08: + * (seebs) Get full paths for exec*() + 2011-01-24: * (mhatle) Revert last result cache and related commits. caching proved to be unreliable. diff --git a/guts/execv.c b/guts/execv.c index a72556b..15ad51e 100644 --- a/guts/execv.c +++ b/guts/execv.c @@ -13,7 +13,9 @@ * design will likely be revisited. */ if (antimagic == 0) { - pseudo_client_op(OP_EXEC, PSA_EXEC, -1, -1, file, 0); + char *path_guess = pseudo_exec_path(file, 0); + pseudo_client_op(OP_EXEC, PSA_EXEC, -1, -1, path_guess, 0); + free(path_guess); } if (!pseudo_get_value("PSEUDO_RELOADED")) diff --git a/guts/execve.c b/guts/execve.c index fafc154..a47b9a7 100644 --- a/guts/execve.c +++ b/guts/execve.c @@ -14,7 +14,9 @@ * design will likely be revisited. */ if (antimagic == 0) { - pseudo_client_op(OP_EXEC, PSA_EXEC, -1, -1, file, 0); + char *path_guess = pseudo_exec_path(file, 0); + pseudo_client_op(OP_EXEC, PSA_EXEC, -1, -1, path_guess, 0); + free(path_guess); } if (!pseudo_get_value("PSEUDO_RELOADED")) diff --git a/guts/execvp.c b/guts/execvp.c index a3ce05b..419f41b 100644 --- a/guts/execvp.c +++ b/guts/execvp.c @@ -14,7 +14,9 @@ * design will likely be revisited. */ if (antimagic == 0) { - pseudo_client_op(OP_EXEC, PSA_EXEC, -1, -1, file, 0); + char *path_guess = pseudo_exec_path(file, 1); + pseudo_client_op(OP_EXEC, PSA_EXEC, -1, -1, path_guess, 0); + free(path_guess); } if (!pseudo_get_value("PSEUDO_RELOADED")) diff --git a/pseudo_client.c b/pseudo_client.c index e96cd31..507796f 100644 --- a/pseudo_client.c +++ b/pseudo_client.c @@ -1240,3 +1240,148 @@ pseudo_stat64_from32(struct stat64 *buf64, struct stat *buf) { buf64->st_mtime = buf->st_mtime; buf64->st_ctime = buf->st_ctime; } + +/* stuff for handling paths and execs */ +static char *previous_path; +static char *previous_path_segs; +static char **path_segs; +static size_t *path_lens; + +/* Makes an array of strings which are the path components + * of previous_path. Does this by duping the path, then replacing + * colons with null terminators, and storing the addresses of the + * starts of the substrings. + */ +static void +populate_path_segs(void) { + size_t len = 0; + char *s; + int c; + + free(path_segs); + free(previous_path_segs); + free(path_lens); + path_segs = NULL; + path_lens = NULL; + previous_path_segs = NULL; + + if (!previous_path) + return; + + for (s = previous_path; *s; ++s) { + if (*s == ':') + ++c; + } + path_segs = malloc((c+2) * sizeof(*path_segs)); + if (!path_segs) { + pseudo_diag("warning: failed to allocate space for %d path segments.\n", + c); + return; + } + path_lens = malloc((c + 2) * sizeof(*path_lens)); + if (!path_lens) { + pseudo_diag("warning: failed to allocate space for %d path lengths.\n", + c); + free(path_segs); + path_segs = 0; + return; + } + previous_path_segs = strdup(previous_path); + if (!previous_path_segs) { + pseudo_diag("warning: failed to allocate space for path copy.\n"); + free(path_segs); + path_segs = NULL; + free(path_lens); + path_lens = NULL; + return; + } + c = 0; + path_segs[c++] = previous_path; + len = 0; + for (s = previous_path; *s; ++s) { + if (*s == ':') { + *s = '\0'; + path_lens[c - 1] = len; + len = 0; + path_segs[c++] = s + 1; + } else { + ++len; + } + } + path_lens[c - 1] = len; + path_segs[c] = NULL; + path_lens[c] = 0; +} + +char * +pseudo_exec_path(const char *filename, int search_path) { + char *path = getenv("PATH"); + char *candidate; + int i; + struct stat buf; + + if (!filename) + return NULL; + + pseudo_antimagic(); + if (!path) { + free(path_segs); + free(previous_path); + path_segs = 0; + previous_path = 0; + } else if (!previous_path || strcmp(previous_path, path)) { + free(previous_path); + previous_path = strdup(path); + populate_path_segs(); + } + + /* absolute paths just get canonicalized. */ + if (*filename == '/') { + candidate = pseudo_fix_path(NULL, filename, 0, 0, NULL, 0); + pseudo_magic(); + return candidate; + } + + if (!search_path) { + candidate = pseudo_fix_path(pseudo_cwd, filename, 0, pseudo_cwd_len, NULL, 0); + /* executable or not, it's the only thing we can try */ + pseudo_magic(); + return candidate; + } + + for (i = 0; path_segs[i]; ++i) { + path = path_segs[i]; + pseudo_debug(2, "exec_path: checking %s for %s\n", path, filename); + if (!*path || (*path == '.' && path_lens[i] == 1)) { + /* empty path or . is cwd */ + candidate = pseudo_fix_path(pseudo_cwd, filename, 0, pseudo_cwd_len, NULL, 0); + pseudo_debug(2, "exec_path: in cwd, got %s\n", candidate); + } else if (*path == '/') { + candidate = pseudo_fix_path(path, filename, 0, path_lens[i], NULL, 0); + pseudo_debug(2, "exec_path: got %s\n", candidate); + } else { + /* oh you jerk, making me do extra work */ + size_t len; + char *dir = pseudo_fix_path(pseudo_cwd, path, 0, pseudo_cwd_len, &len, 0); + if (dir) { + candidate = pseudo_fix_path(dir, filename, 0, len, NULL, 0); + pseudo_debug(2, "exec_path: got %s for non-absolute path\n", candidate); + } else { + pseudo_diag("couldn't allocate intermediate path.\n"); + candidate = NULL; + } + free(dir); + } + if (candidate && !stat(candidate, &buf) && !S_ISDIR(buf.st_mode) && (buf.st_mode & 0111)) { + pseudo_debug(1, "exec_path: %s => %s\n", filename, candidate); + pseudo_magic(); + return candidate; + } else { + free(candidate); + } + } + /* blind guess being as good as anything */ + pseudo_magic(); + return strdup(filename); +} + diff --git a/pseudo_client.h b/pseudo_client.h index 4dc13d0..44d697b 100644 --- a/pseudo_client.h +++ b/pseudo_client.h @@ -53,6 +53,7 @@ extern FILE *pseudo_grp; extern int pseudo_client_getcwd(void); extern int pseudo_client_chroot(const char *); extern char *pseudo_root_path(const char *, int, int, const char *, int); +extern char *pseudo_exec_path(const char *filename, int); #define PSEUDO_ROOT_PATH(x, y, z) pseudo_root_path(__func__, __LINE__, (x), (y), (z)); extern char *pseudo_cwd; extern size_t pseudo_cwd_len; diff --git a/pseudo_util.c b/pseudo_util.c index dc55b0c..704655e 100644 --- a/pseudo_util.c +++ b/pseudo_util.c @@ -590,11 +590,9 @@ pseudo_fix_path(const char *base, const char *path, size_t rootlen, size_t basel *current = '\0'; /* at any given point: * current points to just after the last / of newpath - * path points to the next path element of path + * path points to the next element of path * newpathlen is the total allocated length of newpath - * (current - newpathlen) is the used length of newpath - * oldpath is the starting point of path - * (path - oldpath) is how far into path we are + * (current - newpath) is the used length of newpath */ if (pseudo_append_elements(&newpath, &effective_root, &newpathlen, ¤t, path, pathlen, leave_last) != -1) { --current; |