diff --git a/gcc/fortran/gfortran.texi b/gcc/fortran/gfortran.texi index b1790c6..a5e7cc7 100644 --- a/gcc/fortran/gfortran.texi +++ b/gcc/fortran/gfortran.texi @@ -579,7 +579,7 @@ Malformed environment variables are silently ignored. * GFORTRAN_STDIN_UNIT:: Unit number for standard input * GFORTRAN_STDOUT_UNIT:: Unit number for standard output * GFORTRAN_STDERR_UNIT:: Unit number for standard error -* GFORTRAN_TMPDIR:: Directory for scratch files +* TMPDIR:: Directory for scratch files * GFORTRAN_UNBUFFERED_ALL:: Do not buffer I/O for all units. * GFORTRAN_UNBUFFERED_PRECONNECTED:: Do not buffer I/O for preconnected units. * GFORTRAN_SHOW_LOCUS:: Show location for runtime errors @@ -611,13 +611,26 @@ This environment variable can be used to select the unit number preconnected to standard error. This must be a positive integer. The default value is 0. -@node GFORTRAN_TMPDIR -@section @env{GFORTRAN_TMPDIR}---Directory for scratch files +@node TMPDIR +@section @env{TMPDIR}---Directory for scratch files -This environment variable controls where scratch files are -created. If this environment variable is missing, -GNU Fortran searches for the environment variable @env{TMP}, then @env{TEMP}. -If these are missing, the default is @file{/tmp}. +When opening a file with @code{STATUS='SCRATCH'}, GNU Fortran tries to +create the file in one of the potential directories by testing each +directory in the order below. + +@enumerate +@item +The environment variable @env{TMPDIR}, if it exists. + +@item +On the MingW target, the directory returned by the @code{GetTempPath} +function. Alternatively, on the Cygwin target, the @env{TMP} and +@env{TEMP} environment variables, if they exist, in that order. + +@item +The @code{P_tmpdir} macro if it is defined, otherwise the directory +@file{/tmp}. +@end enumerate @node GFORTRAN_UNBUFFERED_ALL @section @env{GFORTRAN_UNBUFFERED_ALL}---Do not buffer I/O on all units diff --git a/libgfortran/configure.ac b/libgfortran/configure.ac index d70924e..41bef72 100644 --- a/libgfortran/configure.ac +++ b/libgfortran/configure.ac @@ -266,7 +266,7 @@ ftruncate chsize chdir getlogin gethostname kill link symlink sleep ttyname \ alarm access fork execl wait setmode execve pipe dup2 close \ strcasestr getrlimit gettimeofday stat fstat lstat getpwuid vsnprintf dup \ getcwd localtime_r gmtime_r strerror_r getpwuid_r ttyname_r clock_gettime \ -readlink getgid getpid getppid getuid geteuid umask) +readlink getgid getpid getppid getuid geteuid umask getegid __secure_getenv) # Check for C99 (and other IEEE) math functions GCC_CHECK_MATH_FUNC([acosf]) diff --git a/libgfortran/io/unix.c b/libgfortran/io/unix.c index 278decd..f0a8315 100644 --- a/libgfortran/io/unix.c +++ b/libgfortran/io/unix.c @@ -176,6 +176,17 @@ fallback_access (const char *path, int mode) #endif +/* Fallback directory for creating temporary files. P_tmpdir is + defined on many POSIX platforms. */ +#ifndef P_tmpdir +#ifdef _P_tmpdir +#define P_tmpdir _P_tmpdir /* MingW */ +#else +#define P_tmpdir "/tmp" +#endif +#endif + + /* Unix and internal stream I/O module */ static const int BUFFER_SIZE = 8192; @@ -1026,54 +1037,23 @@ unpack_filename (char *cstring, const char *fstring, int len) } -/* tempfile()-- Generate a temporary filename for a scratch file and - * open it. mkstemp() opens the file for reading and writing, but the - * library mode prevents anything that is not allowed. The descriptor - * is returned, which is -1 on error. The template is pointed to by - * opp->file, which is copied into the unit structure - * and freed later. */ +/* Helper function for tempfile(). Tries to open a temporary file in + the directory specified by tempdir. If successful, the file name is + stored in fname and the descriptor returned. Returns -1 on + failure. */ static int -tempfile (st_parameter_open *opp) +tempfile_open (const char * tempdir, char ** fname) { - const char *tempdir; - char *template; - const char *slash = "/"; int fd; - size_t tempdirlen; - -#ifndef HAVE_MKSTEMP - int count; - size_t slashlen; -#endif + const char *slash = "/"; - tempdir = getenv ("GFORTRAN_TMPDIR"); -#ifdef __MINGW32__ - if (tempdir == NULL) - { - char buffer[MAX_PATH + 1]; - DWORD ret; - ret = GetTempPath (MAX_PATH, buffer); - /* If we are not able to get a temp-directory, we use - current directory. */ - if (ret > MAX_PATH || !ret) - buffer[0] = 0; - else - buffer[ret] = 0; - tempdir = strdup (buffer); - } -#else - if (tempdir == NULL) - tempdir = getenv ("TMP"); - if (tempdir == NULL) - tempdir = getenv ("TEMP"); - if (tempdir == NULL) - tempdir = DEFAULT_TEMPDIR; -#endif + if (!tempdir) + return -1; - /* Check for special case that tempdir contains slash + /* Check for special case that tempdir contains slash or backslash at end. */ - tempdirlen = strlen (tempdir); + size_t tempdirlen = strlen (tempdir); if (*tempdir == 0 || tempdir[tempdirlen - 1] == '/' #ifdef __MINGW32__ || tempdir[tempdirlen - 1] == '\\' @@ -1082,7 +1062,7 @@ tempfile (st_parameter_open *opp) slash = ""; // Take care that the template is longer in the mktemp() branch. - template = xmalloc (tempdirlen + 23); + char * template = xmalloc (tempdirlen + 23); #ifdef HAVE_MKSTEMP snprintf (template, tempdirlen + 23, "%s%sgfortrantmpXXXXXX", @@ -1092,8 +1072,8 @@ tempfile (st_parameter_open *opp) #else /* HAVE_MKSTEMP */ fd = -1; - count = 0; - slashlen = strlen (slash); + int count = 0; + size_t slashlen = strlen (slash); do { snprintf (template, tempdirlen + 23, "%s%sgfortrantmpaaaXXXXXX", @@ -1127,8 +1107,58 @@ tempfile (st_parameter_open *opp) while (fd == -1 && errno == EEXIST); #endif /* HAVE_MKSTEMP */ - opp->file = template; - opp->file_len = strlen (template); /* Don't include trailing nul */ + *fname = template; + return fd; +} + +/* tempfile()-- Generate a temporary filename for a scratch file and + * open it. mkstemp() opens the file for reading and writing, but the + * library mode prevents anything that is not allowed. The descriptor + * is returned, which is -1 on error. The template is pointed to by + * opp->file, which is copied into the unit structure + * and freed later. */ + +static int +tempfile (st_parameter_open *opp) +{ + const char *tempdir; + char *fname; + int fd = -1; + + tempdir = secure_getenv ("TMPDIR"); + fd = tempfile_open (tempdir, &fname); +#ifdef __MINGW32__ + if (fd == -1) + { + char buffer[MAX_PATH + 1]; + DWORD ret; + ret = GetTempPath (MAX_PATH, buffer); + /* If we are not able to get a temp-directory, we use + current directory. */ + if (ret > MAX_PATH || !ret) + buffer[0] = 0; + else + buffer[ret] = 0; + tempdir = strdup (buffer); + fd = tempfile_open (tempdir, &fname); + } +#elif defined(__CYGWIN__) + if (fd == -1) + { + tempdir = secure_getenv ("TMP"); + fd = tempfile_open (tempdir, &fname); + } + if (fd == -1) + { + tempdir = secure_getenv ("TEMP"); + fd = tempfile_open (tempdir, &fname); + } +#endif + if (fd == -1) + fd = tempfile_open (P_tmpdir, &fname); + + opp->file = fname; + opp->file_len = strlen (fname); /* Don't include trailing nul */ return fd; } diff --git a/libgfortran/libgfortran.h b/libgfortran/libgfortran.h index be5f133..b2b1162 100644 --- a/libgfortran/libgfortran.h +++ b/libgfortran/libgfortran.h @@ -582,10 +582,6 @@ iexport_data_proto(filename); #define gfc_alloca(x) __builtin_alloca(x) -/* Directory for creating temporary files. Only used when none of the - following environment variables exist: GFORTRAN_TMPDIR, TMP and TEMP. */ -#define DEFAULT_TEMPDIR "/tmp" - /* The default value of record length for preconnected units is defined here. This value can be overriden by an environment variable. Default value is 1 Gb. */ @@ -774,6 +770,18 @@ internal_proto(show_variables); unit_convert get_unformatted_convert (int); internal_proto(get_unformatted_convert); +/* Secure getenv() which returns NULL if running as SUID/SGID. */ +#ifdef HAVE___SECURE_GETENV +#define secure_getenv __secure_getenv +#elif defined(HAVE_GETUID) && defined(HAVE_GETEUID) \ + && defined(HAVE_GETGID) && defined(HAVE_GETEGID) +#define FALLBACK_SECURE_GETENV +extern char *secure_getenv (const char *); +internal_proto(secure_getenv); +#else +#define secure_getenv getenv +#endif + /* string.c */ extern int find_option (st_parameter_common *, const char *, gfc_charlen_type, diff --git a/libgfortran/runtime/environ.c b/libgfortran/runtime/environ.c index 7782cee..0bc0cf3 100644 --- a/libgfortran/runtime/environ.c +++ b/libgfortran/runtime/environ.c @@ -56,6 +56,19 @@ variable; static void init_unformatted (variable *); + +#ifdef FALLBACK_SECURE_GETENV +char * +secure_getenv (const char * name) +{ + if ((getuid () == geteuid ()) && (getgid () == getegid ())) + return getenv (name); + else + return NULL; +} +#endif + + /* print_spaces()-- Print a particular number of spaces. */ static void @@ -285,9 +298,8 @@ static variable variable_table[] = { "Unit number that will be preconnected to standard error\n" "(No preconnection if negative)", 0}, - {"GFORTRAN_TMPDIR", 0, NULL, init_string, show_string, - "Directory for scratch files. Overrides the TMP environment variable\n" - "If TMP is not set " DEFAULT_TEMPDIR " is used.", 0}, + {"TMPDIR", 0, NULL, init_string, show_string, + "Directory for scratch files.", 0}, {"GFORTRAN_UNBUFFERED_ALL", 0, &options.all_unbuffered, init_boolean, show_boolean, diff --git a/libgfortran/runtime/main.c b/libgfortran/runtime/main.c index 79659e5..72c32fc 100644 --- a/libgfortran/runtime/main.c +++ b/libgfortran/runtime/main.c @@ -163,7 +163,7 @@ find_addr2line (void) { #ifdef HAVE_ACCESS #define A2L_LEN 10 - char *path = getenv ("PATH"); + char *path = secure_getenv ("PATH"); if (!path) return; size_t n = strlen (path);