summaryrefslogtreecommitdiff
path: root/luaif/paths.c
diff options
context:
space:
mode:
Diffstat (limited to 'luaif/paths.c')
-rw-r--r--luaif/paths.c789
1 files changed, 660 insertions, 129 deletions
diff --git a/luaif/paths.c b/luaif/paths.c
index a8a9b96..92d5079 100644
--- a/luaif/paths.c
+++ b/luaif/paths.c
@@ -1,8 +1,28 @@
/*
* Copyright (C) 2006,2007 Lauri Leukkunen <lle@rahina.org>
+ * Portion Copyright (c) 2008 Nokia Corporation.
+ * (symlink- and path resolution code refactored by Lauri T. Aarnio at Nokia)
*
* Licensed under LGPL version 2.1, see top level LICENSE file for details.
- */
+ *
+ * ----------------
+ *
+ * This file implements path resolution for SB2. Please read background
+ * information from the "path_resolution" manual page (Linux documentation).
+ *
+ * Path resolution usually belongs to the operating system, but SB2 must
+ * implement a replacement because of one specific feature: Symbolic
+ * links must be mapped. For example, if path "/a/b/c" contains
+ * intermediate symbolic links (i.e. "a" or "b" is a symlink), the path
+ * mapping engine must be called for those all of those symbolic links.
+ *
+ * The division between Lua and C code is that
+ * - C has been used for parts that must follow "standardized" or "fixed"
+ * approach, and the implementation is not expected to be changed, in other
+ * words, the implementation/design freedom is restricted by external
+ * requirements.
+ * - Lua has been used for the mapping algorithm itself.
+*/
#include <unistd.h>
#include <stdio.h>
@@ -35,6 +55,8 @@
#include <mapping.h>
#include <sb2.h>
+#include "libsb2.h"
+#include "exported.h"
#ifdef EXTREME_DEBUGGING
#include <execinfo.h>
@@ -42,36 +64,198 @@
extern int lua_engine_state;
+/* ========== Path & Path component handling primitives: ========== */
+
struct path_entry {
- struct path_entry *prev;
- struct path_entry *next;
- char name[PATH_MAX];
+ struct path_entry *pe_prev;
+ struct path_entry *pe_next;
+ char *pe_last_component_name;
+ char pe_full_path[PATH_MAX];
};
-char *sb_decolonize_path(const char *path)
+struct path_entry_list {
+ struct path_entry *pl_first;
+};
+
+static char *path_entries_to_string(char *buf, struct path_entry *work)
+{
+ *buf = '\0';
+ if (!work) {
+ /* "work" will be empty if orig.path was "/." */
+ strcat(buf, "/");
+ } else while (work) {
+ strcat(buf, "/");
+ strcat(buf, work->pe_last_component_name);
+ work = work->pe_next;
+ }
+
+ return(buf);
+}
+
+static void free_path_entries(struct path_entry_list *listp)
{
- char *cpath, *index, *start;
- char cwd[PATH_MAX + 1];
- struct path_entry list;
struct path_entry *work;
- struct path_entry *new;
- char *buf = NULL;
- if (!path) {
- SB_LOG(SB_LOGLEVEL_ERROR,
- "sb_decolonize_path called with NULL path");
- return NULL;
+ work = listp->pl_first;
+
+ while (work) {
+ struct path_entry *tmp;
+ tmp = work;
+ work = work->pe_next;
+ free(tmp);
}
- buf = malloc((PATH_MAX + 1) * sizeof(char));
- memset(buf, '\0', PATH_MAX + 1);
+ listp->pl_first = NULL;
+}
+
+static void split_path_to_path_entries(
+ char *cpath, /* path buffer; will be modified */
+ struct path_entry_list *listp)
+{
+ struct path_entry *work = NULL;
+ char *start;
+ char tmp_path_buf[PATH_MAX+1];
- list.next = NULL;
- list.prev = NULL;
- work = &list;
+ SB_LOG(SB_LOGLEVEL_NOISE2, "going to split '%s'", cpath);
- if (path[0] != '/') {
+ listp->pl_first = NULL;
+
+ start = cpath;
+ while(*start == '/') start++; /* ignore leading '/' */
+
+ while (1) {
+ unsigned int last = 0;
+ char *index;
+
+ index = strstr(start, "/");
+ if (!index) {
+ last = 1;
+ } else {
+ *index = '\0';
+ }
+
+ /* ignore empty strings resulting from // */
+ if (index != start) {
+ struct path_entry *new;
+
+ /* add an entry to our path_entry list */
+ if (!(new = calloc(1,sizeof(struct path_entry))))
+ abort();
+
+ new->pe_prev = work;
+ if(work) work->pe_next = new;
+
+ new->pe_next = NULL;
+ strcpy(new->pe_full_path, cpath);
+ new->pe_last_component_name = new->pe_full_path + (start-cpath);
+ work = new;
+ if(!listp->pl_first) listp->pl_first = work;
+ SB_LOG(SB_LOGLEVEL_NOISE2,
+ "created entry 0x%X '%s' '%s'",
+ (int)work, work->pe_full_path, start);
+ }
+
+ if (last)
+ break;
+ *index = '/';
+ start = index + 1;
+ }
+ SB_LOG(SB_LOGLEVEL_NOISE2,
+ "split->'%s'", path_entries_to_string(tmp_path_buf, listp->pl_first));
+}
+
+/* remove a path_entry from list, return pointer to the next
+ * path_entry after the removed one (NULL if the removed entry was last)
+*/
+static struct path_entry *remove_path_entry(
+ struct path_entry_list *listp,
+ struct path_entry *p_entry) /* entry to be removed */
+{
+ struct path_entry *ret = p_entry->pe_next;
+
+ if (p_entry->pe_prev) {
+ /* not the first element in the list */
+ p_entry->pe_prev->pe_next = p_entry->pe_next;
+ if(p_entry->pe_next)
+ p_entry->pe_next->pe_prev = p_entry->pe_prev;
+ } else {
+ /* removing first element from the list */
+ assert(p_entry == listp->pl_first);
+ listp->pl_first = p_entry->pe_next;
+ if(p_entry->pe_next)
+ p_entry->pe_next->pe_prev = NULL;
+ }
+ free(p_entry);
+ return(ret);
+}
+
+static void remove_last_path_entry(struct path_entry_list *listp)
+{
+ struct path_entry *work;
+
+ work = listp->pl_first;
+
+ while (work && work->pe_next) {
+ work = work->pe_next;
+ }
+ if (work) {
+ /* now "work" points to last element in the list */
+ remove_path_entry(listp, work);
+ }
+}
+
+static void remove_dots_and_dotdots_from_path_entries(
+ struct path_entry_list *listp)
+{
+ struct path_entry *work;
+ char tmp_path_buf[PATH_MAX+1];
+
+ work = listp->pl_first;
+
+ SB_LOG(SB_LOGLEVEL_NOISE2,
+ "remove_dots_and_dotdots: Clean ->'%s'",
+ path_entries_to_string(tmp_path_buf, listp->pl_first));
+ while (work) {
+ SB_LOG(SB_LOGLEVEL_NOISE2,
+ "remove_dots_and_dotdots: work=0x%X examine '%s'",
+ (int)work, work?work->pe_last_component_name:"");
+ if (strcmp(work->pe_last_component_name, "..") == 0) {
+ struct path_entry *dotdot = work;
+ struct path_entry *preventry = work->pe_prev;
+
+ if (preventry) {
+ /* travel up, and eliminate previous name */
+ work = remove_path_entry(listp, preventry);
+ assert(work == dotdot);
+ } else {
+ /* no preventry, first component is .. */
+ assert(work == listp->pl_first);
+ }
+ work = remove_path_entry(listp, dotdot);
+ } else if (strcmp(work->pe_last_component_name, ".") == 0) {
+ /* ignore this node */
+ work = remove_path_entry(listp, work);
+ } else {
+ work = work->pe_next;
+ }
+ }
+ SB_LOG(SB_LOGLEVEL_NOISE2,
+ "remove_dots_and_dotdots: cleaned->'%s'",
+ path_entries_to_string(tmp_path_buf, listp->pl_first));
+}
+
+static char *absolute_path(const char *path)
+{
+ char *cpath = NULL;
+
+ if (path[0] == '/') {
+ /* already absolute path */
+ if (!(cpath = strdup(path)))
+ abort();
+ } else {
/* not an absolute path */
+ char cwd[PATH_MAX + 1];
+
memset(cwd, '\0', sizeof(cwd));
if (!getcwd(cwd, sizeof(cwd))) {
/* getcwd() returns NULL if the path is really long.
@@ -80,7 +264,7 @@ char *sb_decolonize_path(const char *path)
* must not fail!
*/
SB_LOG(SB_LOGLEVEL_ERROR,
- "sb_decolonize_path failed to get current dir"
+ "absolute_path failed to get current dir"
" (processing continues with relative path)");
if (!(cpath = strdup(path)))
abort();
@@ -89,89 +273,436 @@ char *sb_decolonize_path(const char *path)
if (!cpath)
abort();
}
- } else {
- if (!(cpath = strdup(path)))
- abort();
+ SB_LOG(SB_LOGLEVEL_NOISE, "absolute_path done, '%s'", cpath);
}
+ return(cpath);
+}
- start = cpath;
- while(*start == '/') start++; /* ignore leading '/' */
+char *sb_decolonize_path(const char *path)
+{
+ char *cpath;
+ struct path_entry_list list;
+ char *buf = NULL;
- while (1) {
- unsigned int last = 0;
+ if (!path) {
+ SB_LOG(SB_LOGLEVEL_ERROR,
+ "sb_decolonize_path called with NULL path");
+ return NULL;
+ }
+ SB_LOG(SB_LOGLEVEL_NOISE, "sb_decolonize_path '%s'", path);
- index = strstr(start, "/");
- if (!index) {
- last = 1;
+ list.pl_first = NULL;
+
+ cpath = absolute_path(path);
+
+ split_path_to_path_entries(cpath, &list);
+ remove_dots_and_dotdots_from_path_entries(&list);
+
+ buf = malloc((PATH_MAX + 1) * sizeof(char));
+ memset(buf, '\0', PATH_MAX + 1);
+
+ path_entries_to_string(buf, list.pl_first);
+ free_path_entries(&list);
+
+ SB_LOG(SB_LOGLEVEL_NOISE, "sb_decolonize_path returns '%s'", buf);
+ return buf;
+}
+
+/* dirname() is not thread safe (may return pointer to static buffer),
+ * so we'll have our own version, which always returns absolute dirnames:
+*/
+static char *sb_abs_dirname(const char *path)
+{
+ char *cpath;
+ struct path_entry_list list;
+ char *buf = NULL;
+
+ if (!path) return strdup(".");
+ SB_LOG(SB_LOGLEVEL_NOISE, "sb_abs_dirname '%s'", path);
+
+ list.pl_first = NULL;
+
+ cpath = absolute_path(path);
+
+ split_path_to_path_entries(cpath, &list);
+ remove_last_path_entry(&list);
+
+ buf = malloc((PATH_MAX + 1) * sizeof(char));
+ memset(buf, '\0', PATH_MAX + 1);
+
+ path_entries_to_string(buf, list.pl_first);
+ free_path_entries(&list);
+
+ SB_LOG(SB_LOGLEVEL_NOISE, "sb_abs_dirname returns '%s'", buf);
+ return buf;
+}
+
+/* ========== Other helper functions: ========== */
+
+static char last_char_in_str(const char *str)
+{
+ if (!str || !*str) return('\0');
+ while (str[1]) str++;
+ return(*str);
+}
+
+/* ========== Interfaces to Lua functions: ========== */
+
+static char *call_lua_function_sbox_translate_path(
+ int result_log_level,
+ struct lua_instance *luaif,
+ const char *mapping_mode,
+ const char *binary_name,
+ const char *func_name,
+ const char *work_dir,
+ const char *decolon_path,
+ int *ro_flagp,
+ const char *full_path_for_rule_selection)
+{
+ int ro_flag;
+ char *traslate_result = NULL;
+
+ SB_LOG(SB_LOGLEVEL_NOISE, "calling sbox_translate_path for %s(%s,%s)",
+ func_name, decolon_path, full_path_for_rule_selection);
+
+ lua_getfield(luaif->lua, LUA_GLOBALSINDEX, "sbox_translate_path");
+ lua_pushstring(luaif->lua, mapping_mode);
+ lua_pushstring(luaif->lua, binary_name);
+ lua_pushstring(luaif->lua, func_name);
+ lua_pushstring(luaif->lua, work_dir);
+ lua_pushstring(luaif->lua, decolon_path);
+ lua_pushstring(luaif->lua, full_path_for_rule_selection);
+ lua_call(luaif->lua, 6, 2); /* six arguments, returns path+ro_flag */
+
+ traslate_result = (char *)lua_tostring(luaif->lua, -2);
+ if (traslate_result) {
+ traslate_result = strdup(traslate_result);
+ }
+ ro_flag = lua_toboolean(luaif->lua, -1);
+ if (ro_flagp) *ro_flagp = ro_flag;
+ lua_pop(luaif->lua, 2);
+
+ if (traslate_result) {
+ /* sometimes a mapping rule may create paths that contain
+ * doubled slashes ("//") or end with a slash. We'll
+ * need to clean the path here.
+ */
+ char *cleaned_path;
+
+ cleaned_path = sb_decolonize_path(traslate_result);
+ free(traslate_result);
+ traslate_result = NULL;
+
+ /* log the result */
+ if (strcmp(cleaned_path, decolon_path) == 0) {
+ /* NOTE: Following SB_LOG() call is used by the log
+ * postprocessor script "sb2logz". Do not change
+ * without making a corresponding change to
+ * the script!
+ */
+ SB_LOG(result_log_level, "pass: %s '%s'%s",
+ func_name, decolon_path,
+ (ro_flag ? " (readonly)" : ""));
} else {
- *index = '\0';
+ /* NOTE: Following SB_LOG() call is used by the log
+ * postprocessor script "sb2logz". Do not change
+ * without making a corresponding change to
+ * the script!
+ */
+ SB_LOG(result_log_level, "mapped: %s '%s' -> '%s'%s",
+ func_name, decolon_path, cleaned_path,
+ (ro_flag ? " (readonly)" : ""));
}
+ return cleaned_path;
+ }
+ SB_LOG(SB_LOGLEVEL_ERROR,
+ "No result from sbox_translate_path for: %s '%s'",
+ func_name, decolon_path);
+ return(NULL);
+}
- if (index == start) {
- goto proceed; /* skip over empty strings
- resulting from // */
- }
+/* - returns 1 if ok (then *min_path_lenp is valid)
+ * - returns 0 if failed to find the rule
+*/
+static int call_lua_function_sbox_get_mapping_requirements(
+ struct lua_instance *luaif,
+ const char *mapping_mode,
+ const char *binary_name,
+ const char *func_name,
+ const char *work_dir,
+ const char *full_path_for_rule_selection,
+ int *min_path_lenp)
+{
+ int rule_found;
+ int min_path_len;
- if (strcmp(start, "..") == 0) {
- /* travel up one */
- if (!work->prev)
- goto proceed;
- work = work->prev;
- free(work->next);
- work->next = NULL;
- } else if (strcmp(start, ".") == 0) {
- /* ignore */
- goto proceed;
- } else {
- /* add an entry to our path_entry list */
- if (!(new = malloc(sizeof(struct path_entry))))
- abort();
- memset(new->name, '\0', PATH_MAX);
- new->prev = work;
- work->next = new;
- new->next = NULL;
- strcpy(new->name, start);
- work = new;
+ SB_LOG(SB_LOGLEVEL_NOISE,
+ "calling sbox_get_mapping_requirements for %s(%s)",
+ func_name, full_path_for_rule_selection);
+
+ lua_getfield(luaif->lua, LUA_GLOBALSINDEX,
+ "sbox_get_mapping_requirements");
+ lua_pushstring(luaif->lua, mapping_mode);
+ lua_pushstring(luaif->lua, binary_name);
+ lua_pushstring(luaif->lua, func_name);
+ lua_pushstring(luaif->lua, work_dir);
+ lua_pushstring(luaif->lua, full_path_for_rule_selection);
+ /* five arguments, returns flag+min_path_len */
+ lua_call(luaif->lua, 5, 2);
+
+ rule_found = lua_toboolean(luaif->lua, -2);
+ min_path_len = lua_tointeger(luaif->lua, -1);
+ if (min_path_lenp) *min_path_lenp = min_path_len;
+ lua_pop(luaif->lua, 2);
+
+ SB_LOG(SB_LOGLEVEL_DEBUG, "sbox_get_mapping_requirements -> %d,%d",
+ rule_found, min_path_len);
+
+ return(rule_found);
+}
+
+/* ========== Path resolution: ==========
+ * This is the place where symlinks are followed.
+ * Returns an allocated buffer containing the resolved path (or NULL if error)
+ *
+ * FIXME: It might be possible to eliminate parameter
+ * "full_path_for_rule_selection" now when the separate call to
+ * sbox_get_mapping_requirements is used to ensure that "path" is long
+ * enough. However, this has been left to be done in the future, together
+ * with other optimizations.
+*/
+static char *sb_path_resolution(
+ int nest_count,
+ struct lua_instance *luaif,
+ const char *mapping_mode,
+ const char *binary_name,
+ const char *func_name,
+ const char *work_dir,
+ const char *path,
+ const char *full_path_for_rule_selection,
+ int dont_resolve_final_symlink)
+{
+ char *cpath;
+ struct path_entry_list orig_path_list;
+ char *buf = NULL;
+ struct path_entry *work;
+ int component_index = 0;
+ int min_path_len_to_check;
+
+ if (nest_count > 16) {
+ SB_LOG(SB_LOGLEVEL_ERROR,
+ "sb_path_resolution: too deep nesting "
+ "(too many symbolic links");
+
+ /* FIXME: This should return ELOOP to the calling program,
+ * but that does not happen currently, because there is no
+ * proper way to signal this kind of failures in the mapping
+ * phase. This is somewhat complex to fix; the fix requires
+ * that the mapping engine interface and other places must
+ * be changed, too (e.g. the interface generator, etc).
+ * This is minor problem currently.
+ */
+ errno = ELOOP;
+ return NULL;
+ }
+
+ if (!path) {
+ SB_LOG(SB_LOGLEVEL_ERROR,
+ "sb_path_resolution called with NULL path");
+ return NULL;
+ }
+
+ SB_LOG(SB_LOGLEVEL_NOISE,
+ "sb_path_resolution %d '%s'", nest_count, path);
+
+ orig_path_list.pl_first = NULL;
+
+ cpath = absolute_path(path);
+
+ split_path_to_path_entries(cpath, &orig_path_list);
+
+ work = orig_path_list.pl_first;
+
+ if (call_lua_function_sbox_get_mapping_requirements(
+ luaif, mapping_mode, binary_name, func_name,
+ work_dir, full_path_for_rule_selection,
+ &min_path_len_to_check)) {
+ /* has requirements:
+ * skip over path components that we are not supposed to check,
+ * because otherwise rule recognition & execution could fail.
+ */
+ while ((int)strlen(work->pe_full_path) < min_path_len_to_check) {
+ SB_LOG(SB_LOGLEVEL_NOISE2, "skipping [%d] '%s'",
+ component_index, work->pe_last_component_name);
+ component_index++;
+ work = work->pe_next;
}
+ }
-proceed:
- if (last)
+ /* Path resolution loop = walk thru directories, and if a symlink
+ * is found, recurse..
+ */
+ while (work) {
+ char link_dest[PATH_MAX];
+ char decolon_tmp[PATH_MAX];
+ int link_len;
+ char *prefix_mapping_result;
+ struct path_entry_list prefix_path_list;
+ int ro_tmp;
+
+ if (dont_resolve_final_symlink && (work->pe_next == NULL)) {
+ /* this is last component, but here a final symlink
+ * must not be resolved (calls like lstat(), rename(),
+ * etc)
+ */
+ SB_LOG(SB_LOGLEVEL_NOISE2,
+ "Won't check last component [%d] '%s'",
+ component_index, work->pe_full_path);
break;
- *index = '/';
- start = index + 1;
- }
+ }
- work = list.next;
- if (!work) {
- /* "work" will be empty if orig.path was "/." */
- strcat(buf, "/");
- } else while (work) {
- struct path_entry *tmp;
- strcat(buf, "/");
- strcat(buf, work->name);
- tmp = work;
- work = work->next;
- free(tmp);
+ SB_LOG(SB_LOGLEVEL_NOISE2, "test [%d] '%s'",
+ component_index, work->pe_full_path);
+
+ prefix_path_list.pl_first = NULL;
+ split_path_to_path_entries(work->pe_full_path, &prefix_path_list);
+ remove_dots_and_dotdots_from_path_entries(&prefix_path_list);
+ path_entries_to_string(decolon_tmp, prefix_path_list.pl_first);
+ free_path_entries(&prefix_path_list);
+
+ prefix_mapping_result = call_lua_function_sbox_translate_path(
+ SB_LOGLEVEL_NOISE,
+ luaif, mapping_mode, binary_name, "PATH_RESOLUTION",
+ work_dir, decolon_tmp, &ro_tmp,
+ full_path_for_rule_selection);
+
+ SB_LOG(SB_LOGLEVEL_NOISE2, "prefix_mapping_result='%s'",
+ prefix_mapping_result);
+
+ /* determine if "prefix_mapping_result" is a symbolic link.
+ * this can't be done with lstat(), because lstat() does not
+ * exist as a function on Linux => lstat_nomap() can not be
+ * used eiher. fortunately readlink() is an ordinary function.
+ */
+ link_len = readlink_nomap(prefix_mapping_result, link_dest, PATH_MAX);
+
+ if (link_len > 0) {
+ /* was a symlink */
+ char new_path[PATH_MAX];
+ char rest_of_path[PATH_MAX];
+
+ link_dest[link_len] = '\0';
+ if (work->pe_next) {
+ path_entries_to_string(rest_of_path, work->pe_next);
+ } else {
+ /* last component of the path was a symlink. */
+ *rest_of_path = '\0';
+ }
+ SB_LOG(SB_LOGLEVEL_NOISE,
+ "is symlink: rest='%s'", rest_of_path);
+
+ if (*link_dest == '/') {
+ /* absolute symlink.
+ * This is easy: just join the symlink
+ * and rest of path, and further mapping
+ * operations will take care of the rest.
+ */
+ SB_LOG(SB_LOGLEVEL_NOISE,
+ "absolute symlink at '%s' "
+ "points to '%s', restarting",
+ prefix_mapping_result, link_dest);
+ strcpy(new_path, link_dest);
+ if (*rest_of_path) {
+ if ((last_char_in_str(new_path) != '/')
+ && (*rest_of_path != '/')) {
+ strcat(new_path, "/");
+ }
+ strcat(new_path, rest_of_path);
+ }
+ } else {
+ /* A relative symlink. Somewhat complex:
+ * "prefix_mapping_result" contains the
+ * real location in the FS, but here we
+ * must still build the full path from the
+ * place where we pretend to be - otherwise
+ * path mapping code would fail to find the
+ * correct location. Hence "dirnam" is
+ * based on what was mapped, and not based on
+ * were the mapping took us.
+ */
+ char *dirnam;
+
+ dirnam = sb_abs_dirname(work->pe_full_path);
+
+ SB_LOG(SB_LOGLEVEL_NOISE,
+ "relative symlink at '%s' "
+ "points to '%s'",
+ prefix_mapping_result, link_dest);
+ strcpy(new_path, dirnam);
+ if (last_char_in_str(new_path) != '/')
+ strcat(new_path, "/");
+ strcat(new_path, link_dest);
+ if (*rest_of_path) {
+ if ((last_char_in_str(new_path) != '/')
+ && (*rest_of_path != '/')) {
+ strcat(new_path, "/");
+ }
+ strcat(new_path, rest_of_path);
+ }
+ free(dirnam);
+ }
+ free(prefix_mapping_result);
+ free_path_entries(&orig_path_list);
+
+ /* recursively call myself to perform path
+ * resolution steps for the symlink target.
+ */
+ return(sb_path_resolution(nest_count + 1,
+ luaif, mapping_mode, binary_name, func_name,
+ work_dir, new_path,
+ new_path, dont_resolve_final_symlink));
+ }
+ free(prefix_mapping_result);
+ work = work->pe_next;
+ component_index++;
}
+
+ /* All symbolic links have been resolved.
+ *
+ * Since there are no symlinks in "orig_path_list", "." and ".."
+ * entries can be safely removed:
+ */
+ remove_dots_and_dotdots_from_path_entries(&orig_path_list);
+
+ buf = malloc((PATH_MAX + 1) * sizeof(char));
+ memset(buf, '\0', PATH_MAX + 1);
+
+ path_entries_to_string(buf, orig_path_list.pl_first);
+ free_path_entries(&orig_path_list);
+
SB_LOG(SB_LOGLEVEL_NOISE,
- "sb_decolonize_path returns '%s'", buf);
+ "sb_path_resolution returns '%s'", buf);
return buf;
}
+/* ========== Public interfaces to the mapping & resolution code: ========== */
+
/* make sure to use disable_mapping(m);
- * to prevent recursive calls to this function
+ * to prevent recursive calls to this function.
+ * Returns a pointer to an allocated buffer which contains the result.
*/
char *scratchbox_path3(const char *binary_name,
const char *func_name,
const char *path,
const char *mapping_mode,
- int *ro_flagp)
+ int *ro_flagp,
+ int dont_resolve_final_symlink)
{
char work_dir[PATH_MAX + 1];
- char *tmp = NULL, *decolon_path = NULL;
- char pidlink[17]; /* /proc/2^8/exe */
struct lua_instance *luaif;
- int ro_flag;
+ char *mapping_result;
+
+ SB_LOG(SB_LOGLEVEL_DEBUG, "scratchbox_path3: %s(%s)", func_name, path);
#ifdef EXTREME_DEBUGGING
#define SIZE 100
@@ -184,6 +715,10 @@ char *scratchbox_path3(const char *binary_name,
for (i = 0; i < nptrs; i++)
SB_LOG(SB_LOGLEVEL_DEBUG, "%s\n", strings[i]);
#endif
+ if (!path || !*path) {
+ /* an empty path shall always remain empty */
+ return strdup("");
+ }
switch (lua_engine_state) {
case LES_NOT_INITIALIZED:
@@ -236,61 +771,57 @@ char *scratchbox_path3(const char *binary_name,
}
disable_mapping(luaif);
- decolon_path = sb_decolonize_path(path);
-
- if (!decolon_path) {
- SB_LOG(SB_LOGLEVEL_ERROR,
- "ERROR: scratchbox_path3: decolon_path failed [%s]",
- func_name);
- return NULL;
- }
-
- memset(work_dir, '\0', PATH_MAX+1);
- snprintf(pidlink, sizeof(pidlink), "/proc/%i/exe", getpid());
- getcwd(work_dir, PATH_MAX);
-
- lua_getfield(luaif->lua, LUA_GLOBALSINDEX, "sbox_translate_path");
- lua_pushstring(luaif->lua, mapping_mode);
- lua_pushstring(luaif->lua, binary_name);
- lua_pushstring(luaif->lua, func_name);
- lua_pushstring(luaif->lua, work_dir);
- lua_pushstring(luaif->lua, decolon_path);
- lua_call(luaif->lua, 5, 2); /* five arguments, returns path+ro_flag */
-
- tmp = (char *)lua_tostring(luaif->lua, -2);
- if (tmp) {
- tmp = strdup(tmp);
+ {
+ /* Mapping disabled inside this block - do not use "return"!! */
+ char *decolon_path = NULL;
+ char *full_path_for_rule_selection;
+
+ full_path_for_rule_selection = sb_decolonize_path(path);
+
+ /* FIXME: work_dir should be unnecessary if path is absolute? */
+ memset(work_dir, '\0', sizeof(work_dir));
+ getcwd(work_dir, sizeof(work_dir)-1);
+
+ SB_LOG(SB_LOGLEVEL_DEBUG,
+ "scratchbox_path3: process '%s', n='%s'",
+ path, full_path_for_rule_selection);
+ decolon_path = sb_path_resolution(0,
+ luaif, mapping_mode, binary_name, func_name,
+ work_dir, path, full_path_for_rule_selection,
+ dont_resolve_final_symlink);
+
+ if (!decolon_path) {
+ SB_LOG(SB_LOGLEVEL_ERROR,
+ "ERROR: scratchbox_path3: decolon_path failed [%s]",
+ func_name);
+ mapping_result = NULL;
+ } else {
+ SB_LOG(SB_LOGLEVEL_NOISE2,
+ "scratchbox_path3: decolon_path='%s'"
+ " work_dir='%s'",
+ decolon_path, work_dir);
+
+ mapping_result = call_lua_function_sbox_translate_path(
+ SB_LOGLEVEL_INFO,
+ luaif, mapping_mode, binary_name, func_name,
+ work_dir, decolon_path, ro_flagp,
+ decolon_path);
+ }
+ if(decolon_path) free(decolon_path);
+ if(full_path_for_rule_selection) free(full_path_for_rule_selection);
}
- ro_flag = lua_toboolean(luaif->lua, -1);
- if (ro_flagp) *ro_flagp = ro_flag;
-
- lua_pop(luaif->lua, 2);
-
enable_mapping(luaif);
- if (strcmp(tmp, decolon_path) == 0) {
- free(decolon_path);
- free(tmp);
- /* NOTE: Following SB_LOG() call is used by the log
- * postprocessor script "sb2logz". Do not change
- * without making a corresponding change to the script!
- */
- SB_LOG(SB_LOGLEVEL_INFO, "pass: %s '%s'%s",
- func_name, path, (ro_flag ? " (readonly)" : ""));
- return strdup(path);
- } else {
- free(decolon_path);
- /* NOTE: Following SB_LOG() call is used by the log
- * postprocessor script "sb2logz". Do not change
- * without making a corresponding change to the script!
- */
- SB_LOG(SB_LOGLEVEL_INFO, "mapped: %s '%s' -> '%s'%s",
- func_name, path, tmp, (ro_flag ? " (readonly)" : ""));
- return tmp;
- }
+ SB_LOG(SB_LOGLEVEL_NOISE2, "scratchbox_path3: mapping_result='%s'",
+ mapping_result ? mapping_result : "<No result>");
+ return(mapping_result);
}
-char *scratchbox_path(const char *func_name, const char *path, int *ro_flagp)
+char *scratchbox_path(
+ const char *func_name,
+ const char *path,
+ int *ro_flagp,
+ int dont_resolve_final_symlink)
{
char binary_name[PATH_MAX+1];
char *bin_name;
@@ -306,6 +837,6 @@ char *scratchbox_path(const char *func_name, const char *path, int *ro_flagp)
mapping_mode = "simple";
}
return (scratchbox_path3(binary_name, func_name, path, mapping_mode,
- ro_flagp));
+ ro_flagp, dont_resolve_final_symlink));
}