summaryrefslogtreecommitdiffstats
path: root/misc.c
diff options
context:
space:
mode:
authorDavid Sommerseth <dazo@users.sourceforge.net>2010-04-16 22:02:36 +0200
committerDavid Sommerseth <dazo@users.sourceforge.net>2010-10-21 11:37:03 +0200
commit4e1cc5f6dda22e9ff121d3753066775c25448bcc (patch)
treed58ab37fedc0795d2b4c75b4f500a66e1aa415e6 /misc.c
parent41104b4e23aaa17257cadb7f6c4ba1325c025b46 (diff)
downloadopenvpn-4e1cc5f6dda22e9ff121d3753066775c25448bcc.tar.gz
openvpn-4e1cc5f6dda22e9ff121d3753066775c25448bcc.tar.xz
openvpn-4e1cc5f6dda22e9ff121d3753066775c25448bcc.zip
Harden create_temp_filename() (version 2)
By hardening the create_temp_filename() function to check if the generated filename exists and to create the temp file with only S_IRUSR|S_IWUSR bit files set before calling the script, it should become even more difficult to exploit such a scenario. After a discussion on the mailing list, Fabian Knittel provided an enhanced version of the inital patch which is added to this patch. This patch also renames create_temp_filename() to create_temp_file(), as this patch also creates the temporary file. The function returns the filename of the created file, or NULL on error. Signed-off-by: David Sommerseth <dazo@users.sourceforge.net> Signed-off-by: Fabian Knittel <fabian.knittel@avona.com> Acked-by: Gert Doering <gert@greenie.muc.de>
Diffstat (limited to 'misc.c')
-rw-r--r--misc.c60
1 files changed, 46 insertions, 14 deletions
diff --git a/misc.c b/misc.c
index 507bcc2..0ceeb2d 100644
--- a/misc.c
+++ b/misc.c
@@ -1165,25 +1165,57 @@ test_file (const char *filename)
/* create a temporary filename in directory */
const char *
-create_temp_filename (const char *directory, const char *prefix, struct gc_arena *gc)
+create_temp_file (const char *directory, const char *prefix, struct gc_arena *gc)
{
static unsigned int counter;
struct buffer fname = alloc_buf_gc (256, gc);
+ int fd;
+ const char *retfname = NULL;
+ unsigned int attempts = 0;
- mutex_lock_static (L_CREATE_TEMP);
- ++counter;
- mutex_unlock_static (L_CREATE_TEMP);
-
- {
- uint8_t rndbytes[16];
- const char *rndstr;
-
- prng_bytes (rndbytes, sizeof (rndbytes));
- rndstr = format_hex_ex (rndbytes, sizeof (rndbytes), 40, 0, NULL, gc);
- buf_printf (&fname, PACKAGE "_%s_%s.tmp", prefix, rndstr);
- }
+ do
+ {
+ uint8_t rndbytes[16];
+ const char *rndstr;
+
+ ++attempts;
+ mutex_lock_static (L_CREATE_TEMP);
+ ++counter;
+ mutex_unlock_static (L_CREATE_TEMP);
+
+ prng_bytes (rndbytes, sizeof rndbytes);
+ rndstr = format_hex_ex (rndbytes, sizeof rndbytes, 40, 0, NULL, gc);
+ buf_printf (&fname, PACKAGE "_%s_%s.tmp", prefix, rndstr);
+
+ retfname = gen_path (directory, BSTR (&fname), gc);
+ if (!retfname)
+ {
+ msg (M_FATAL, "Failed to create temporary filename and path");
+ return NULL;
+ }
+
+ /* Atomically create the file. Errors out if the file already
+ exists. */
+ fd = open (retfname, O_CREAT | O_EXCL | O_WRONLY, S_IRUSR | S_IWUSR);
+ if (fd != -1)
+ {
+ close (fd);
+ return retfname;
+ }
+ else if (fd == -1 && errno != EEXIST)
+ {
+ /* Something else went wrong, no need to retry. */
+ struct gc_arena gcerr = gc_new ();
+ msg (M_FATAL, "Could not create temporary file '%s': %s",
+ retfname, strerror_ts (errno, &gcerr));
+ gc_free (&gcerr);
+ return NULL;
+ }
+ }
+ while (attempts < 6);
- return gen_path (directory, BSTR (&fname), gc);
+ msg (M_FATAL, "Failed to create temporary file after %i attempts", attempts);
+ return NULL;
}
/*