diff options
author | David Sommerseth <dazo@users.sourceforge.net> | 2010-04-16 22:02:36 +0200 |
---|---|---|
committer | David Sommerseth <dazo@users.sourceforge.net> | 2010-04-29 20:22:29 +0200 |
commit | cb042f8eb2de4908072f3b1c11149d60a74eae28 (patch) | |
tree | f42e95dd5217bf00e2828bbd459cee706668ff60 | |
parent | Make use of counter_type instead of int when counting bytes and network packets (diff) | |
download | openvpn-cb042f8eb2de4908072f3b1c11149d60a74eae28.tar.xz |
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>
-rw-r--r-- | misc.c | 60 | ||||
-rw-r--r-- | misc.h | 4 |
2 files changed, 48 insertions, 16 deletions
@@ -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; } /* @@ -218,8 +218,8 @@ long int get_random(void); /* return true if filename can be opened for read */ bool 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 a temporary file in directory, returns the filename of the created file */ +const char *create_temp_file (const char *directory, const char *prefix, struct gc_arena *gc); /* put a directory and filename together */ const char *gen_path (const char *directory, const char *filename, struct gc_arena *gc); |