summaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
authorGravatar Federico Mena Quintero2013-07-02 13:38:36 -0500
committerGravatar Federico Mena Quintero2013-07-02 20:31:45 -0500
commita2ddca0916ef776dbd0c6304ea36b4ca7a35302c (patch)
treed744dbf3df01d57a6fea739181fa525d8ea2e97f /common
parent42892465d4522cf19283b8a06bf48104bb387430 (diff)
downloadlibimobiledevice-a2ddca0916ef776dbd0c6304ea36b4ca7a35302c.tar.gz
libimobiledevice-a2ddca0916ef776dbd0c6304ea36b4ca7a35302c.tar.bz2
Bug #331 - Don't create a /tmp/root directory insecurely
When finding the user's home directory to generate a subdirectory in $HOME/.config, we would fall back to /tmp if there were no environment variables for HOME or XDG_CONFIG_HOME. Since libimobiledevice gets used by upower, and since upowerd runs as root, this would cause a /tmp/root directory to be created insecurely, leaving upowerd vulnerable to a symlink attack. Now we fall back to getpwuid_r() to find the user's home directory if it is not provided in environment variables - this is the case when upowerd gets run via systemd, for example. The result is that we'll end up creating /root/.config, a safe directory, since regular users cannot create symlinks in /root. In the future we'll need a way for libimobiledevice to find where to store its pairing data on behalf of the console user, rather than writing it to /root. http://libiphone.lighthouseapp.com/projects/27916-libiphone/tickets/331-insecure-tmp-directory-use
Diffstat (limited to 'common')
-rw-r--r--common/userpref.c105
1 files changed, 76 insertions, 29 deletions
diff --git a/common/userpref.c b/common/userpref.c
index d363b0e..ab3a3cf 100644
--- a/common/userpref.c
+++ b/common/userpref.c
@@ -26,6 +26,9 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <unistd.h>
#ifdef HAVE_OPENSSL
#include <openssl/pem.h>
#include <openssl/rsa.h>
@@ -48,6 +51,7 @@
#include "userpref.h"
#include "debug.h"
+#include "utils.h"
#define LIBIMOBILEDEVICE_CONF_DIR "libimobiledevice"
#define LIBIMOBILEDEVICE_CONF_FILE "libimobiledevicerc"
@@ -65,7 +69,7 @@
#define DIR_SEP_S "/"
#endif
-static char __config_dir[512] = {0, };
+static char *__config_dir = NULL;
#ifdef WIN32
static char *userpref_utf16_to_utf8(wchar_t *unistr, long len, long *items_read, long *items_written)
@@ -103,24 +107,60 @@ static char *userpref_utf16_to_utf8(wchar_t *unistr, long len, long *items_read,
#endif
#ifndef WIN32
-static const char *userpref_get_tmp_dir()
+static char *get_home_dir_from_system(void)
{
- const char *cdir = getenv("TMPDIR");
- if (cdir && cdir[0])
- return cdir;
- cdir = getenv("TMP");
- if (cdir && cdir[0])
- return cdir;
- cdir = getenv("TEMP");
- if (cdir && cdir[0])
- return cdir;
- return "/tmp";
+ long bufsize;
+ char *buf;
+ int error;
+ struct passwd pwd;
+ struct passwd *ppwd;
+ char *result = NULL;
+
+ bufsize = sysconf (_SC_GETPW_R_SIZE_MAX);
+
+ if (bufsize < 0)
+ bufsize = 1024;
+
+ buf = NULL;
+
+ do {
+ free (buf);
+ buf = malloc (bufsize);
+ if (!buf)
+ return NULL;
+
+ errno = 0;
+ error = getpwuid_r (getuid (), &pwd, buf, bufsize, &ppwd);
+
+ error = (error < 0) ? errno : error;
+
+ if (!ppwd) {
+ if (error == 0 || error == ENOENT)
+ break;
+ else if (bufsize > 32 * 1024)
+ break; /* Unreasonable size; let's bail out */
+
+ bufsize *= 2;
+ }
+ } while (!ppwd);
+
+ if (ppwd && ppwd->pw_dir)
+ result = strdup (ppwd->pw_dir);
+
+ free (buf);
+
+ return result;
}
#endif
static const char *userpref_get_config_dir()
{
- if (__config_dir[0]) return __config_dir;
+ char *base_config_dir;
+ int use_dot_config;
+
+ if (__config_dir)
+ return __config_dir;
+
#ifdef WIN32
wchar_t path[MAX_PATH+1];
HRESULT hr;
@@ -131,38 +171,45 @@ static const char *userpref_get_config_dir()
if (hr == S_OK) {
b = SHGetPathFromIDListW (pidl, path);
if (b) {
- char *cdir = userpref_utf16_to_utf8 (path, wcslen(path), NULL, NULL);
- strcpy(__config_dir, cdir);
- free(cdir);
+ base_config_dir = userpref_utf16_to_utf8 (path, wcslen(path), NULL, NULL);
CoTaskMemFree (pidl);
}
}
+
+ use_dot_config = 0;
#else
const char *cdir = getenv("XDG_CONFIG_HOME");
if (!cdir) {
cdir = getenv("HOME");
if (!cdir || !cdir[0]) {
- const char *tdir = userpref_get_tmp_dir();
- strcpy(__config_dir, tdir);
- strcat(__config_dir, DIR_SEP_S);
- strcat(__config_dir, "root");
+ base_config_dir = get_home_dir_from_system();
+ if (!base_config_dir)
+ return NULL;
} else {
- strcpy(__config_dir, cdir);
+ base_config_dir = strdup(cdir);
}
- strcat(__config_dir, DIR_SEP_S);
- strcat(__config_dir, ".config");
+
+ use_dot_config = 1;
} else {
- strcpy(__config_dir, cdir);
+ base_config_dir = strdup(cdir);
+ use_dot_config = 0;
}
#endif
- strcat(__config_dir, DIR_SEP_S);
- strcat(__config_dir, LIBIMOBILEDEVICE_CONF_DIR);
- int i = strlen(__config_dir)-1;
- while ((i > 0) && (__config_dir[i] == DIR_SEP)) {
- __config_dir[i--] = '\0';
+ if (use_dot_config)
+ __config_dir = string_concat(base_config_dir, DIR_SEP_S, ".config", DIR_SEP_S, LIBIMOBILEDEVICE_CONF_DIR);
+ else
+ __config_dir = string_concat(base_config_dir, DIR_SEP_S, LIBIMOBILEDEVICE_CONF_DIR);
+
+ if (__config_dir) {
+ int i = strlen(__config_dir)-1;
+ while ((i > 0) && (__config_dir[i] == DIR_SEP)) {
+ __config_dir[i--] = '\0';
+ }
}
+ free(base_config_dir);
+
return __config_dir;
}