[asterisk-commits] dlee: branch dlee/record r391268 - in /team/dlee/record: include/asterisk/ ma...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Mon Jun 10 10:22:59 CDT 2013
Author: dlee
Date: Mon Jun 10 10:22:56 2013
New Revision: 391268
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=391268
Log:
Attempt at restricting the recording directory.
Modified:
team/dlee/record/include/asterisk/utils.h
team/dlee/record/main/utils.c
team/dlee/record/res/res_stasis_recording.c
team/dlee/record/res/stasis_http/resource_channels.c
team/dlee/record/tests/test_utils.c
Modified: team/dlee/record/include/asterisk/utils.h
URL: http://svnview.digium.com/svn/asterisk/team/dlee/record/include/asterisk/utils.h?view=diff&rev=391268&r1=391267&r2=391268
==============================================================================
--- team/dlee/record/include/asterisk/utils.h (original)
+++ team/dlee/record/include/asterisk/utils.h Mon Jun 10 10:22:56 2013
@@ -717,6 +717,19 @@
* Creates a directory path, creating parent directories as needed.
*/
int ast_mkdir(const char *path, int mode);
+
+/*!
+ * \brief Recursively create directory path, but only if it resolves within
+ * the given \a base_path.
+ *
+ * If \a base_path does not exist, it will not be created and this function
+ * returns \c EPERM.
+ *
+ * \param path The directory path to create
+ * \param mode The permissions with which to try to create the directory
+ * \return 0 on success or an error code otherwise
+ */
+int ast_safe_mkdir(const char *base_path, const char *path, int mode);
#define ARRAY_LEN(a) (size_t) (sizeof(a) / sizeof(0[a]))
Modified: team/dlee/record/main/utils.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/record/main/utils.c?view=diff&rev=391268&r1=391267&r2=391268
==============================================================================
--- team/dlee/record/main/utils.c (original)
+++ team/dlee/record/main/utils.c Mon Jun 10 10:22:56 2013
@@ -2092,6 +2092,70 @@
return errno;
}
return 0;
+}
+
+static int safe_mkdir(const char *base_path, char *path, int mode)
+{
+ RAII_VAR(char *, absolute_path, NULL, free);
+
+ absolute_path = realpath(path, NULL);
+
+ if (absolute_path) {
+ /* Path exists, but is it in the right place? */
+ if (!ast_begins_with(absolute_path, base_path)) {
+ return EPERM;
+ }
+
+ /* It is in the right place! */
+ return 0;
+ } else {
+ char *last_slash = strrchr(path, '/');
+ int res;
+
+ if (last_slash == path) {
+ /* Parent is the root directory. */
+ res = EPERM;
+ } else if (last_slash == NULL) {
+ /* No more parents. */
+ res = EPERM;
+ } else {
+ /* Safely build the parent. */
+ *last_slash = '\0';
+ res = safe_mkdir(base_path, path, mode);
+ *last_slash = '/';
+ }
+
+ if (res != 0) {
+ /* Return failure */
+ errno = res;
+ return res;
+ }
+
+ /* Parent created, now create this path */
+ return safe_mkdir(base_path, path, mode);
+ }
+}
+
+int ast_safe_mkdir(const char *base_path, const char *path, int mode)
+{
+ RAII_VAR(char *, absolute_base_path, NULL, free);
+ RAII_VAR(char *, p, NULL, ast_free);
+
+ if (base_path == NULL || path == NULL) {
+ return EFAULT;
+ }
+
+ p = ast_strdup(path);
+ if (p == NULL) {
+ return ENOMEM;
+ }
+
+ absolute_base_path = realpath(base_path, NULL);
+ if (absolute_base_path == NULL) {
+ return ENOENT;
+ }
+
+ return safe_mkdir(absolute_base_path, p, mode);
}
int ast_utils_init(void)
Modified: team/dlee/record/res/res_stasis_recording.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/record/res/res_stasis_recording.c?view=diff&rev=391268&r1=391267&r2=391268
==============================================================================
--- team/dlee/record/res/res_stasis_recording.c (original)
+++ team/dlee/record/res/res_stasis_recording.c Mon Jun 10 10:22:56 2013
@@ -135,19 +135,19 @@
return STASIS_APP_RECORDING_TERMINATE_NONE;
}
- if (strcmp(str, "none") == 0) {
+ if (strcasecmp(str, "none") == 0) {
return STASIS_APP_RECORDING_TERMINATE_NONE;
}
- if (strcmp(str, "any") == 0) {
+ if (strcasecmp(str, "any") == 0) {
return STASIS_APP_RECORDING_TERMINATE_ANY;
}
- if (strcmp(str, "#") == 0) {
+ if (strcasecmp(str, "#") == 0) {
return '#';
}
- if (strcmp(str, "*") == 0) {
+ if (strcasecmp(str, "*") == 0) {
return '*';
}
@@ -162,15 +162,15 @@
return STASIS_APP_RECORDING_IF_EXISTS_FAIL;
}
- if (strcmp(str, "fail") == 0) {
+ if (strcasecmp(str, "fail") == 0) {
return STASIS_APP_RECORDING_IF_EXISTS_FAIL;
}
- if (strcmp(str, "overwrite") == 0) {
+ if (strcasecmp(str, "overwrite") == 0) {
return STASIS_APP_RECORDING_IF_EXISTS_OVERWRITE;
}
- if (strcmp(str, "append") == 0) {
+ if (strcasecmp(str, "append") == 0) {
return STASIS_APP_RECORDING_IF_EXISTS_APPEND;
}
@@ -453,12 +453,8 @@
return NULL;
}
- if (options->name[0] == '/') {
- recording->absolute_name = ast_strdup(options->name);
- } else {
- ast_asprintf(&recording->absolute_name, "%s/%s",
- ast_config_AST_RECORDING_DIR, options->name);
- }
+ ast_asprintf(&recording->absolute_name, "%s/%s",
+ ast_config_AST_RECORDING_DIR, options->name);
if (recording->absolute_name == NULL) {
errno = ENOMEM;
@@ -467,7 +463,8 @@
if ((last_slash = strrchr(recording->absolute_name, '/'))) {
*last_slash = '\0';
- if (ast_mkdir(recording->absolute_name, 0777) != 0) {
+ if (ast_safe_mkdir(ast_config_AST_RECORDING_DIR,
+ recording->absolute_name, 0777) != 0) {
/* errno set by ast_mkdir */
return NULL;
}
Modified: team/dlee/record/res/stasis_http/resource_channels.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/record/res/stasis_http/resource_channels.c?view=diff&rev=391268&r1=391267&r2=391268
==============================================================================
--- team/dlee/record/res/stasis_http/resource_channels.c (original)
+++ team/dlee/record/res/stasis_http/resource_channels.c Mon Jun 10 10:22:56 2013
@@ -295,7 +295,15 @@
response, 500, "Internal Server Error",
"Out of memory");
break;
+ case EPERM:
+ stasis_http_response_error(
+ response, 400, "Bad Request",
+ "Recording name invalid");
+ break;
default:
+ ast_log(LOG_WARNING,
+ "Unrecognized recording error: %s\n",
+ strerror(errno));
stasis_http_response_error(
response, 500, "Internal Server Error",
"Internal Server Error");
Modified: team/dlee/record/tests/test_utils.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/record/tests/test_utils.c?view=diff&rev=391268&r1=391267&r2=391268
==============================================================================
--- team/dlee/record/tests/test_utils.c (original)
+++ team/dlee/record/tests/test_utils.c Mon Jun 10 10:22:56 2013
@@ -42,6 +42,8 @@
#include "asterisk/channel.h"
#include "asterisk/module.h"
+#include <sys/stat.h>
+
AST_TEST_DEFINE(uri_encode_decode_test)
{
int res = AST_TEST_PASS;
@@ -421,6 +423,93 @@
return res;
}
+AST_TEST_DEFINE(safe_mkdir_test)
+{
+ char base_path[] = "/tmp/safe_mkdir.XXXXXX";
+ char path[80] = {};
+ int res;
+ struct stat actual;
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = __func__;
+ info->category = "/main/utils/";
+ info->summary = "Safe mkdir test";
+ info->description =
+ "This test ensures that ast_safe_mkdir does what it is "
+ "supposed to";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ if (mkdtemp(base_path) == NULL) {
+ ast_test_status_update(test, "Failed to create tmpdir for test\n");
+ return AST_TEST_FAIL;
+ }
+
+ snprintf(path, sizeof(path), "%s/should_work", base_path);
+ res = ast_safe_mkdir(base_path, path, 0777);
+ ast_test_validate(test, 0 == res);
+ res = stat(path, &actual);
+ ast_test_validate(test, 0 == res);
+ ast_test_validate(test, S_ISDIR(actual.st_mode));
+
+ snprintf(path, sizeof(path), "%s/should/also/work", base_path);
+ res = ast_safe_mkdir(base_path, path, 0777);
+ ast_test_validate(test, 0 == res);
+ res = stat(path, &actual);
+ ast_test_validate(test, 0 == res);
+ ast_test_validate(test, S_ISDIR(actual.st_mode));
+
+ snprintf(path, sizeof(path), "%s/even/this/../should/work", base_path);
+ res = ast_safe_mkdir(base_path, path, 0777);
+ ast_test_validate(test, 0 == res);
+ snprintf(path, sizeof(path), "%s/even/should/work", base_path);
+ res = stat(path, &actual);
+ ast_test_validate(test, 0 == res);
+ ast_test_validate(test, S_ISDIR(actual.st_mode));
+
+ snprintf(path, sizeof(path),
+ "%s/surprisingly/this/should//////////////////work", base_path);
+ res = ast_safe_mkdir(base_path, path, 0777);
+ ast_test_validate(test, 0 == res);
+ snprintf(path, sizeof(path),
+ "%s/surprisingly/this/should/work", base_path);
+ res = stat(path, &actual);
+ ast_test_validate(test, 0 == res);
+ ast_test_validate(test, S_ISDIR(actual.st_mode));
+
+ snprintf(path, sizeof(path), "/should_not_work");
+ res = ast_safe_mkdir(base_path, path, 0777);
+ ast_test_validate(test, 0 != res);
+ ast_test_validate(test, EPERM == errno);
+ res = stat(path, &actual);
+ ast_test_validate(test, 0 != res);
+ ast_test_validate(test, ENOENT == errno);
+
+ snprintf(path, sizeof(path), "%s/../nor_should_this", base_path);
+ res = ast_safe_mkdir(base_path, path, 0777);
+ ast_test_validate(test, 0 != res);
+ ast_test_validate(test, EPERM == errno);
+ strncpy(path, "/tmp/nor_should_this", sizeof(path));
+ res = stat(path, &actual);
+ ast_test_validate(test, 0 != res);
+ ast_test_validate(test, ENOENT == errno);
+
+ snprintf(path, sizeof(path),
+ "%s/this/especially/should/not/../../../../work", base_path);
+ res = ast_safe_mkdir(base_path, path, 0777);
+ ast_test_validate(test, 0 != res);
+ ast_test_validate(test, EPERM == errno);
+ strncpy(path, "/tmp/work", sizeof(path));
+ res = stat(path, &actual);
+ ast_test_validate(test, 0 != res);
+ ast_test_validate(test, ENOENT == errno);
+
+ return AST_TEST_PASS;
+}
+
static int unload_module(void)
{
AST_TEST_UNREGISTER(uri_encode_decode_test);
@@ -431,6 +520,7 @@
AST_TEST_UNREGISTER(crypto_loaded_test);
AST_TEST_UNREGISTER(adsi_loaded_test);
AST_TEST_UNREGISTER(agi_loaded_test);
+ AST_TEST_UNREGISTER(safe_mkdir_test);
return 0;
}
@@ -444,6 +534,7 @@
AST_TEST_REGISTER(crypto_loaded_test);
AST_TEST_REGISTER(adsi_loaded_test);
AST_TEST_REGISTER(agi_loaded_test);
+ AST_TEST_REGISTER(safe_mkdir_test);
return AST_MODULE_LOAD_SUCCESS;
}
More information about the asterisk-commits
mailing list