From c21172a6f60e1265f1c6dcd57147fde9c90e03bf Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Sun, 18 Dec 2011 17:53:21 +0000 Subject: [PATCH] Create a secure temp path instead of a predictable one (Thanks Han) With this commit, i3 will now use either $XDG_RUNTIME_DIR/i3 (XDG_RUNTIME_DIR is only writable by the user, so this is not a problem) or a secure temporary location in /tmp, following the pattern /tmp/i3-.XXXXXX --- docs/ipc | 6 ++++-- docs/userguide | 11 ++++++---- man/i3.man | 7 ++++--- src/util.c | 39 ++++++++++++++++++++++------------- testcases/t/159-socketpaths.t | 11 ++++++++++ 5 files changed, 51 insertions(+), 23 deletions(-) diff --git a/docs/ipc b/docs/ipc index fc46590e..61a85c0a 100644 --- a/docs/ipc +++ b/docs/ipc @@ -11,8 +11,10 @@ workspace bar. The method of choice for IPC in our case is a unix socket because it has very little overhead on both sides and is usually available without headaches in most languages. In the default configuration file, the ipc-socket gets created -in +/tmp/i3-%u/ipc-socket.%p+ where +%u+ is your UNIX username and +%p+ is the -PID of i3. You can get the socketpath from i3 by calling +i3 --get-socketpath+. +in +/tmp/i3-%u.XXXXXX/ipc-socket.%p+ where +%u+ is your UNIX username, +%p+ is +the PID of i3 and XXXXXX is a string of random characters from the portable +filename character set (see mkdtemp(3)). You can get the socketpath from i3 by +calling +i3 --get-socketpath+. All i3 utilities, like +i3-msg+ and +i3-input+ will read the +I3_SOCKET_PATH+ X11 property, stored on the X11 root window. diff --git a/docs/userguide b/docs/userguide index 3d78d16f..be8335ef 100644 --- a/docs/userguide +++ b/docs/userguide @@ -643,16 +643,19 @@ programs to get information from i3, such as the current workspaces (to display a workspace bar), and to control i3. The IPC socket is enabled by default and will be created in -+/tmp/i3-%u/ipc-socket.%p+ where +%u+ is your UNIX username and +%p+ is the PID -of i3. ++/tmp/i3-%u.XXXXXX/ipc-socket.%p+ where +%u+ is your UNIX username, +%p+ is +the PID of i3 and XXXXXX is a string of random characters from the portable +filename character set (see mkdtemp(3)). You can override the default path through the environment-variable +I3SOCK+ or by specifying the +ipc-socket+ directive. This is discouraged, though, since i3 -does the right thing by default. +does the right thing by default. If you decide to change it, it is strongly +recommended to set this to a location in your home directory so that no other +user can create that directory. *Examples*: ---------------------------- -ipc-socket /tmp/i3-ipc.sock +ipc-socket ~/.i3/i3-ipc.sock ---------------------------- You can then use the +i3-msg+ application to perform any command listed in diff --git a/man/i3.man b/man/i3.man index 019c9124..2e14fce7 100644 --- a/man/i3.man +++ b/man/i3.man @@ -294,9 +294,10 @@ exec /usr/bin/i3 -V -d all >> ~/.i3/logfile === I3SOCK This variable overwrites the IPC socket path (placed in -/tmp/i3-%u/ipc-socket.%p by default, where %u is replaced with your UNIX -username and %p is replaced with i3’s PID). The IPC socket is used by external -programs like i3-msg(1) or i3bar(1). +/tmp/i3-%u.XXXXXX/ipc-socket.%p by default, where %u is replaced with your UNIX +username, %p is replaced with i3’s PID and XXXXXX is a string of random +characters from the portable filename character set (see mkdtemp(3))). The IPC +socket is used by external programs like i3-msg(1) or i3bar(1). == TODO diff --git a/src/util.c b/src/util.c index 72146bff..ba0b2c4b 100644 --- a/src/util.c +++ b/src/util.c @@ -234,25 +234,36 @@ static char **append_argument(char **original, char *argument) { * */ char *get_process_filename(const char *prefix) { - char *dir = getenv("XDG_RUNTIME_DIR"); + /* dir stores the directory path for this and all subsequent calls so that + * we only create a temporary directory once per i3 instance. */ + static char *dir = NULL; if (dir == NULL) { - struct passwd *pw = getpwuid(getuid()); - const char *username = pw ? pw->pw_name : "unknown"; - sasprintf(&dir, "/tmp/i3-%s", username); - } else { - char *tmp; - sasprintf(&tmp, "%s/i3", dir); - dir = tmp; - } - if (!path_exists(dir)) { - if (mkdir(dir, 0700) == -1) { - perror("mkdir()"); - return NULL; + /* Check if XDG_RUNTIME_DIR is set. If so, we use XDG_RUNTIME_DIR/i3 */ + if ((dir = getenv("XDG_RUNTIME_DIR"))) { + char *tmp; + sasprintf(&tmp, "%s/i3", dir); + dir = tmp; + if (!path_exists(dir)) { + if (mkdir(dir, 0700) == -1) { + perror("mkdir()"); + return NULL; + } + } + } else { + /* If not, we create a (secure) temp directory using the template + * /tmp/i3-.XXXXXX */ + struct passwd *pw = getpwuid(getuid()); + const char *username = pw ? pw->pw_name : "unknown"; + sasprintf(&dir, "/tmp/i3-%s.XXXXXX", username); + /* mkdtemp modifies dir */ + if (mkdtemp(dir) == NULL) { + perror("mkdtemp()"); + return NULL; + } } } char *filename; sasprintf(&filename, "%s/%s.%d", dir, prefix, getpid()); - free(dir); return filename; } diff --git a/testcases/t/159-socketpaths.t b/testcases/t/159-socketpaths.t index eb6bd79f..b9cc9b63 100644 --- a/testcases/t/159-socketpaths.t +++ b/testcases/t/159-socketpaths.t @@ -20,9 +20,20 @@ EOT # ensure XDG_RUNTIME_DIR is not set delete $ENV{XDG_RUNTIME_DIR}; + +# See which files exist in /tmp before to not mistakenly check an already +# existing tmpdir of another i3 instance. +my @files_before = ; my $pid = launch_with_config($config, 1); +my @files_after = ; +@files_after = grep { !($_ ~~ @files_before) } @files_after; + +is(@files_after, 1, 'one new temp directory'); my $folder = "/tmp/i3-" . getpwuid(getuid()); +like($files_after[0], qr/^$folder/, 'temp directory matches expected pattern'); +$folder = $files_after[0]; + ok(-d $folder, "folder $folder exists"); my $socketpath = "$folder/ipc-socket." . $pid; ok(-S $socketpath, "file $socketpath exists and is a socket");