C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

temporary functions

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
joel
Guest





PostPosted: Tue Mar 15, 2005 12:00 am    Post subject: temporary functions Reply with quote





Hello group,

I will appreciate it if somebody could give me a good explanation about
difference among
temporary functions in C++/C programming.

There are different fucntions i.e mktemp, mkstemp, tempnam, tmpfile and
also tmpnam() but
how should I know which one should be used for a particular situation?

The reason I'm asking this is becuase curretnly I'm working on
somebody's else project and he
had used:


char tempPath[L_tmpnam];
::tmpnam(tempPath);

Please consider that above function (::tmpnam()) is used in a function
that must return a boolean value. But it neither
returns false nor true but when I change it to mkstemp() it does!!!

Is there any function that do a better job than this one?


Any comment? I will really apprciate sharing your ideas.

Thanks,


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
R Samuel Klatchko
Guest





PostPosted: Tue Mar 15, 2005 3:52 pm    Post subject: Re: temporary functions Reply with quote



joel wrote:
Quote:
There are different fucntions i.e mktemp, mkstemp, tempnam, tmpfile and
also tmpnam() but
how should I know which one should be used for a particular situation?

The functions can roughly be grouped into a 2/2 matrix, with one axis
being whether the function just generates a name or also opens the file
and a second axis by having control over the name generated.


name only / control of name
mktemp
tempnam

name and open file / control of name
mkstemp

name only / no control of name
tmpnam

name and open file / control of name
tmpfile

Picking one depends on how you need to use the data. If you want to
create a directory, you'll have to generate just the name and create the
directory yourself. Also, do you want to control the name of the file
(which includes the directory) or are you satisfied with letter the
standard library do that for you.

There are also some other differences. tmpfile() creates a file that
will go away when the handle is closed while mkstemp() requires the
program to unlink the file (of course, this gives you the benefit of
having the file persist across program invocations if you need that).

Finally, if you are not having the function create the file, be careful
of race conditions. The function can only check whether the file name
is in use within itself. So there is the possibility that in between
returning from the function and calling the file create function, the
name can be used. If for some reason you still want to create the file
yourself, make sure you use the O_EXCL flag and be prepared to loop and
eventually fail if you can't create the file.

samuel

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
kanze@gabi-soft.fr
Guest





PostPosted: Tue Mar 15, 2005 3:59 pm    Post subject: Re: temporary functions Reply with quote



joel wrote:

Quote:
I will appreciate it if somebody could give me a good
explanation about difference among temporary functions in
C++/C programming.

Just a nit, but the functions themselves aren't temporary. (I
couldn't figure out what you were talking about from the subject
line itself.)

Quote:
There are different fucntions i.e mktemp, mkstemp, tempnam,
tmpfile and also tmpnam() but how should I know which one
should be used for a particular situation?

First, only tmpfile and tmpnam are standard; the others are
implementation specific extensions, and should be avoided in
portable code.

For completeness: mktemp is Posix, but is marked as legacy, and
so should definitely be avoided; mkstemp is also legacy Unix,
but not even defined in Posix, so would be even worse, and
tempnam requires you to specify the directory where the file
goes; logically, it's none of your business if you want a true
temporary file, but IF you are on a Posix system or Linux, and
you expect later to "rename" the file to make it permanent, this
is the one to use, since renaming can be significantly more
rapid if the target and the original are on the same file
system.

For most purposes, however, you should restrict yourself to
tmpnam and tmpfile -- tmpfile has the advantage of taking care
of removal itself, and avoiding any race conditions (if
implemented correctly, of course); tmpnam allows you to control
removal of the files (possibly offering an option of not
deleting them for debugging purposes), and using them with
iostreams (rather than just FILE*). I also like to be able to
output the file name in case of errors, but of course, my users
are generally pretty savey with regards to computer technology.
Correctly implemented, the probability of a race condition is
practically nul, and can for all practical purposes be ignored.

Finally, when I need a certain number of temporary files, I'll
generally create a directory with the temporary name, put
the files (with significant names) in there, and finish with
something like `system( (std::string( "rm -r " ) +
myTempname).c_str() )'. This, of course, also requires
tmpnam().

(Note that normally, the system should use some sort of
conventions so that even if your temporary file doesn't get
removed for some reason, the system will remove it itself at
some point in time. Thus, for example, under Solaris, tmpnam
always generates a file name in /var/tmp, a directory which is
normally "cleaned up" when the system boots.)

Quote:
The reason I'm asking this is becuase curretnly I'm working on
somebody's else project and he had used:

char tempPath[L_tmpnam];
::tmpnam(tempPath);

Please consider that above function (::tmpnam()) is used in a
function
that must return a boolean value.

Used as above, it doesn't matter what ::tmpnam() returns. In
fact, tmpnam returns a char*, which is null if the function
fails, and points to the generated string if it succeeds; if you
pass a non-null pointer, you can use it as a boolean value,
returning true on success.

Quote:
But it neither returns false nor true but when I change it to
mkstemp() it does!!!

Is there any function that do a better job than this one?

Any comment? I will really apprciate sharing your ideas.

I'd say that in C++ (where you definitly want to use iostream,
and not FILE*), the only usable solution is tmpnam(), EXCEPT in
the case where you want to rename the file later, and so want
the temporary file in the final target directory (and you are
restricting your portability to Posix and similar systems). The
only problem I see is that the quality of implementation of
tmpnam is not generally very good -- when I implemented it, I
used an environment variable to override the default directory
(which allows a work-around at the user level in case the
default temporary directory isn't big enough), and I mangled the
process id into the name as well, and used a couple of special
characters, as well as generating a number of characters in a
random fashion, so the chancees of an accidental collision were
pratically zero. Most of the implementations I've seen limit
themselves to the random characters (which is still sufficient
for most purposes).

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Carlos Moreno
Guest





PostPosted: Tue Mar 15, 2005 9:05 pm    Post subject: Re: temporary functions Reply with quote

[email]kanze (AT) gabi-soft (DOT) fr[/email] wrote:

Quote:
I will appreciate it if somebody could give me a good
explanation about difference among temporary functions in
C++/C programming.

Just a nit, but the functions themselves aren't temporary. (I
couldn't figure out what you were talking about from the subject
line itself.)

I had this exact same reaction when reading the subject
line -- my only guess (before reading the message) was
that he might have been talking about unnamed temporary
function objects as in, e.g.: sort (begin, end, cmp())

Carlos
--

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
R Samuel Klatchko
Guest





PostPosted: Tue Mar 15, 2005 9:12 pm    Post subject: Re: temporary functions Reply with quote

[email]kanze (AT) gabi-soft (DOT) fr[/email] wrote:
Quote:
First, only tmpfile and tmpnam are standard; the others are
implementation specific extensions, and should be avoided in
portable code.

For completeness: mktemp is Posix, but is marked as legacy, and
so should definitely be avoided; mkstemp is also legacy Unix,
but not even defined in Posix, so would be even worse, and
tempnam requires you to specify the directory where the file
goes;

I'm not sure about the Posix standard, but both mkstemp() and and
tempnam() are part of the Single Unix Spec. You can find more
information at:

http://www.opengroup.org/onlinepubs/009695399/toc.htm

samuel

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Ben Hutchings
Guest





PostPosted: Tue Mar 15, 2005 9:12 pm    Post subject: Re: temporary functions Reply with quote

joel wrote:
Quote:
Hello group,

I will appreciate it if somebody could give me a good explanation
about difference among temporary functions in C++/C programming.

There are different fucntions i.e mktemp, mkstemp, tempnam, tmpfile
and also tmpnam() but how should I know which one should be used for
a particular situation?
snip


tmpnam() and tmpfile() are part of the standard library and therefore
more portable than the others.

tmpfile() should be fine if you do not need to know the name of the
temporary file. I tend to create temporary files in order to pass
information to external programs or with the intention of closing them
and reopening them later, so I do not find it useful.

tmpnam() is problematic in a multitasking system because there is a
race condition between generation of the filename and creation of the
file, so it is possible to overwrite an existing file rather than
creating a new one. In some implementations (e.g. VC++) it may select
an inappropriate directory in which to create temporary files.
Finally, if it selects a common temporary directory, such as /tmp on
Unix, the race condition becomes a security flaw. I strongly
recommend you avoid using it.

tempnam() is a widely available extended version of tmpnam that at
least gives some control over the directory used for temporary files.
If you can choose a private temporary directory for the process then
you can avoid the problems I noted.

mktemp() is a Unix-specific function similar to tempnam() but more
limited in the way it generates names. It is not very useful.

mkstemp() is similar to mktemp() but actually creates the file before
returning, guaranteeing that it is unique. It is still not very
useful due to the limited number of names it can generate.

Note that aside from tmpfile() these all leave you with the job of
cleaning up the temporary files.

I don't believe there is a good secure way of creating temporary files
that is also portable. My preferred method is to create a private
temporary directory under the standard temporary directory (creating a
directory normally doesn't overwrite an existing directory) and then
creaate files within there. This is also more efficient because the
process controls all the files in that directory and does not need to
perform existence tests before generating a new name.

Here's an outline of how to do the name generation:

using std::string;
using std::stringstream;

#if defined(_WIN32)
inline string system_temp_dir()
{
char buf[MAX_PATH];
if (!GetTempPath(MAX_PATH, buf))
abort(); // well, there might be a better way to handle this
return buf;
}
inline DWORD process_id() { return GetCurrentProcessId(); }
const char path_separator = '\';
inline bool create_dir(const std::string & name)
{
return CreateDirectory(name, NULL) != 0;
}
#elif defined(__unix__)
inline string system_temp_dir()
{
if (const char * env = getenv("TMPDIR"))
return env;
else
return "/tmp";
}
inline int process_id() { return getpid(); }
const char path_separator = '/';
inline bool create_dir(const std::string & name)
{
return mkdir(name, 0700) == 0;
}
#else
// You'll have to work out how to do this on other platforms.
#endif

string make_temp_dir()
{
stringstream ss;
ss << system_temp_dir()
<< path_separator
<< "myappname-"
<< process_id();
string name(ss.str());
if (create_dir(name))
return name;
// else try adding something to the end of the name; really
// you need a loop here to generate more names
}

string temp_dir_name()
{
static string name = make_temp_dir();
return name;
}

string temp_file_name()
{
static unsigned long counter = 0;
stringstream ss;
ss << temp_dir_name() << path_separator << counter++;
// it may be worth testing for counter overflow here,
// though 4 billion files "should be enough for anyone"
return ss.str();
}

This leaves the problem of removing temporary files when they are no
longer needed. It is probably best to define a class encapsulating
temporary files which deletes the file in its destructor, rather than
simply passing names around. The temporary directory can be
encapsulated in a singleton class whose directory deletes that as
well.

--
Ben Hutchings
Having problems with C++ templates? Your questions may be answered by

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
kanze@gabi-soft.fr
Guest





PostPosted: Thu Mar 17, 2005 2:27 am    Post subject: Re: temporary functions Reply with quote

R Samuel Klatchko wrote:
Quote:
joel wrote:
There are different fucntions i.e mktemp, mkstemp, tempnam,
tmpfile and also tmpnam() but how should I know which one
should be used for a particular situation?

[...]

Quote:
Finally, if you are not having the function create the file,
be careful of race conditions. The function can only check
whether the file name is in use within itself.

If that is all the function checks, it is not conform, at least
in the case of tmpnam. The C standard requires that: "The
tmpnam function generates a string that is a valid file name and
that is not the same as the name of an existing file." There is
still a race condition; another process could create a file with
that name between the moment you call tmpnam and the moment you
try to create the temporary file. A good implementation of
tmpnam will take steps to minimize this risk, e.g. but using the
current process id as part of the name, and by using special
characters which are unlikely to occur in a user specified
name. And on most systems, there are additional conventions
which play a role; on Unix based systems, for example, users do
not normally specify files in directories such as /tmp or
/var/tmp, so generating a name in one of these directories
effectively limits the risk of user defined names.

Quote:
So there is the possibility that in between returning from the
function and calling the file create function, the name can be
used. If for some reason you still want to create the file
yourself, make sure you use the O_EXCL flag and be prepared to
loop and eventually fail if you can't create the file.

With a good implementation of tmpnam, the probability of having
to loop is probably negligible. But why not; a little extra
precaution never hurts. (And not all implementations of tmpnam
are that good:-).)

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
kanze@gabi-soft.fr
Guest





PostPosted: Thu Mar 17, 2005 2:37 am    Post subject: Re: temporary functions Reply with quote

Ben Hutchings wrote:
Quote:
joel wrote:

I will appreciate it if somebody could give me a good
explanation about difference among temporary functions in
C++/C programming.

tmpnam() is problematic in a multitasking system because there
is a race condition between generation of the filename and
creation of the file, so it is possible to overwrite an
existing file rather than creating a new one.

That's more or less true for any function which returns a
filename, and not an open file. Depending on the system, there
are more or less effective work-arounds, e.g. using O_EXCL when
creating the file under Unix. With a quality implementation,
the probability of an accidental name collision can be made
sufficiently small to be acceptable too. (Obviously, it depends
on what the program does. An "acceptable" risk for a compiler
would probably not be acceptable for a program running as
super-user and managing some critical system resource.)

Quote:
In some implementations (e.g. VC++) it may select an
inappropriate directory in which to create temporary files.

I don't know about VC++, but this is a problem with the version
g++ under Linux. Under Solaris, it's acceptable, although in my
own implementations, I tend to make the default directory
overridable by means of an environment variable.

Quote:
Finally, if it selects a common temporary directory, such as
/tmp on Unix, the race condition becomes a security flaw. I
strongly recommend you avoid using it.

I'm not sure I see the security flaw unless you get sloppy about
creating the file. Under Unix, for example, using
open( name, O_RW | O_CREAT | O_EXCL, 0x600 )
should be about as secure as you can get, and I'd be surprised
if Windows didn't have similar options.

Of course, this means you need to use the usual extension (which
should be present in any quality implementation where it makes
sense) to initialize a filebuf with a system level file
descriptor.

And of course, the security risk depends largely on what the
program is doing. In something like a compiler, I wouldn't
worry about it. In more critical software, using open as above
will limit it -- if the hacker can read the file you created
thusly, he can probably read your core image in /proc as well,
and so see the data directly in memory.

[...]
Quote:
Note that aside from tmpfile() these all leave you with the
job of cleaning up the temporary files.

Which can be a decided advantage when debugging:-).

Quote:
I don't believe there is a good secure way of creating
temporary files that is also portable.

Only because filebuf (and fopen) don't allow access to all of
the necessary underlying flags for the system level open.

Quote:
My preferred method is to create a private temporary directory
under the standard temporary directory (creating a directory
normally doesn't overwrite an existing directory) and then
creaate files within there. This is also more efficient
because the process controls all the files in that directory
and does not need to perform existence tests before generating
a new name.

It's the method I prefer as well, WHEN I need several different
temporary files. Especially because on my systems, at least, I
can delete the directory structure recursively with a single
call to "system".

Quote:
Here's an outline of how to do the name generation:

using std::string;
using std::stringstream;

#if defined(_WIN32)
inline string system_temp_dir()
{
char buf[MAX_PATH];
if (!GetTempPath(MAX_PATH, buf))
abort(); // well, there might be a better way to
handle this
return buf;
}
inline DWORD process_id() { return GetCurrentProcessId(); }
const char path_separator = '\';
inline bool create_dir(const std::string & name)
{
return CreateDirectory(name, NULL) != 0;
}
#elif defined(__unix__)
inline string system_temp_dir()
{
if (const char * env = getenv("TMPDIR"))
return env;
else
return "/tmp";

This is not necessarily the best default for Unix. Most current
Unix implementations use the same hardware partition for the
virtual memory and /tmp. This means that 1) /tmp is typically
pretty small, 2) you are completing with virtual memory to use
it, and 3) accidentally filling it up isn't a very good idea.
Normally, /var/tmp is to be preferred.

Also, there is no standard environment variable name for this --
I usually use $TEMP, which wouldn't work with your
implementation. In practice, I generally loop over a list of
filenames:
$TMP
$TEMP
$TMPDIR
$TEMPDIR
$HOME/tmp
/var/tmp
/tmp
and use the first one which exists and is an accessible
directory (system calls access and fstat).

Quote:
}
inline int process_id() { return getpid(); }
const char path_separator = '/';
inline bool create_dir(const std::string & name)
{
return mkdir(name, 0700) == 0;
}
#else
// You'll have to work out how to do this on other platforms.
#endif

string make_temp_dir()
{
stringstream ss;
ss << system_temp_dir()
path_separator
"myappname-"
process_id();
string name(ss.str());
if (create_dir(name))
return name;
// else try adding something to the end of the name; really
// you need a loop here to generate more names
}

Adding a random value to the name helps. As does using some
characters which don't usuall appear in filenames, things like
# or * (or starting the name with a - under Unix).

Quote:
string temp_dir_name()
{
static string name = make_temp_dir();
return name;
}

string temp_file_name()
{
static unsigned long counter = 0;
stringstream ss;
ss << temp_dir_name() << path_separator << counter++;
// it may be worth testing for counter overflow here,
// though 4 billion files "should be enough for anyone"
return ss.str();
}

This leaves the problem of removing temporary files when they
are no longer needed. It is probably best to define a class
encapsulating temporary files which deletes the file in its
destructor, rather than simply passing names around. The
temporary directory can be encapsulated in a singleton class
whose directory deletes that as well.

I'd add an option to suppress the deletion as well. It's very
nice to have the temp files hang around when debugging.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Ben Hutchings
Guest





PostPosted: Thu Mar 17, 2005 8:14 am    Post subject: Re: temporary functions Reply with quote

I wrote:
<snip>
Quote:
The temporary directory can be encapsulated in a singleton class
whose directory deletes that as well.

Er, make that "...whose destructor deletes that..."

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
R Samuel Klatchko
Guest





PostPosted: Fri Mar 18, 2005 1:08 pm    Post subject: Re: temporary functions Reply with quote

[email]kanze (AT) gabi-soft (DOT) fr[/email] wrote:
Quote:
Finally, if you are not having the function create the file,
be careful of race conditions. The function can only check
whether the file name is in use within itself.

If that is all the function checks, it is not conform, at least
in the case of tmpnam. The C standard requires that: "The
tmpnam function generates a string that is a valid file name and
that is not the same as the name of an existing file." There is
still a race condition; another process could create a file with
that name between the moment you call tmpnam and the moment you
try to create the temporary file.

Thanks. That was actually what I was trying to say although in
retrospect, I did a very poor job of it.

Quote:
So there is the possibility that in between returning from the
function and calling the file create function, the name can be
used. If for some reason you still want to create the file
yourself, make sure you use the O_EXCL flag and be prepared to
loop and eventually fail if you can't create the file.

With a good implementation of tmpnam, the probability of having
to loop is probably negligible. But why not; a little extra
precaution never hurts. (And not all implementations of tmpnam
are that good:-).)

Perhaps, but I have had to debug too many situations where conventional
wisdom held that a case was not worth handling because the case was too
rare.

In my mind, there are two cases. Either something is guaranteed (to
always or never happen) or not. If it's not guaranteed, then code must
check what happened.

I would be fine (but not thrilled) to have some code use O_EXCL on the
filename and just fail if the race condition happens. But I wouldn't
hesitate to throw out code that didn't use O_EXCL because the case is rare.

samuel

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
James Kanze
Guest





PostPosted: Mon Mar 21, 2005 12:01 am    Post subject: Re: temporary functions Reply with quote

R Samuel Klatchko wrote:
Quote:
kanze (AT) gabi-soft (DOT) fr wrote:

[...]

Quote:
With a good implementation of tmpnam, the probability of
having to loop is probably negligible. But why not; a little
extra precaution never hurts. (And not all implementations of
tmpnam are that good:-).)

Perhaps, but I have had to debug too many situations where
conventional wisdom held that a case was not worth handling
because the case was too rare.

The question isn't only frequency. It also concerns what
happens when the case occurs.

In the case of Unix, for example, people shouldn't normally be
creating files in /var/tmp without some sort of naming
convention to keep them separated, e.g. by introducing the pid
into the file name somewhere. Of course, you can't prevent it,
but for something like a compiler, I could accept that it failed
because it was unable to create a temporary file if such a thing
happened. For more critical programs, of course, no.

Quote:
In my mind, there are two cases. Either something is
guaranteed (to always or never happen) or not.

I agree that on any robust system, the something like tmpnam
would involve a system call, and result in a name that could not
be generated otherwise. But robust systems are pretty rare.

Quote:
If it's not guaranteed, then code must check what happened.

Or do something that will provoke failure if it happens:-).

Quote:
I would be fine (but not thrilled) to have some code use
O_EXCL on the filename and just fail if the race condition
happens. But I wouldn't hesitate to throw out code that
didn't use O_EXCL because the case is rare.

Agreed. With one exception, perhaps: a quick test program that
you are going to throw out anyway.

--
James Kanze home: www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 pl. Pierre Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Ben Hutchings
Guest





PostPosted: Tue Mar 22, 2005 9:07 am    Post subject: Re: temporary functions Reply with quote

[email]kanze (AT) gabi-soft (DOT) fr[/email] wrote:
Quote:
Ben Hutchings wrote:
joel wrote:

I will appreciate it if somebody could give me a good
explanation about difference among temporary functions in
C++/C programming.

tmpnam() is problematic in a multitasking system because there
is a race condition between generation of the filename and
creation of the file, so it is possible to overwrite an
existing file rather than creating a new one.
snip
Finally, if it selects a common temporary directory, such as
/tmp on Unix, the race condition becomes a security flaw. I
strongly recommend you avoid using it.

I'm not sure I see the security flaw unless you get sloppy about
creating the file. Under Unix, for example, using
open( name, O_RW | O_CREAT | O_EXCL, 0x600 )
should be about as secure as you can get, and I'd be surprised
if Windows didn't have similar options.

Sure, but if you're going to have to use non-standard functions why
bother using tmpnam() to generate the name?

Quote:
Of course, this means you need to use the usual extension (which
should be present in any quality implementation where it makes
sense) to initialize a filebuf with a system level file
descriptor.

And of course, the security risk depends largely on what the
program is doing. In something like a compiler, I wouldn't
worry about it.

The risk is not just information leakage but also denial of service.
If the temporary files are being created by a process running as root,
carefully timed creation of a symbolic link pointing to /dev/kmem
might have some interesting results. If they are being created by
an ordinary user then any of their files with predictable names could
also be overwritten.

Quote:
In more critical software, using open as above
will limit it -- if the hacker can read the file you created
thusly, he can probably read your core image in /proc as well,
and so see the data directly in memory.

Right.

<snip>
Quote:
I don't believe there is a good secure way of creating
temporary files that is also portable.

Only because filebuf (and fopen) don't allow access to all of
the necessary underlying flags for the system level open.

Right. It would be useful to be able to specify such flags, but
perhaps not every filesystem implementation supports them.
(Actually I know NFS doesn't support O_EXCL before version 3,
and NFS clients just fudge it rather than failing the call.)

<snip>
Quote:
#elif defined(__unix__)
inline string system_temp_dir()
{
if (const char * env = getenv("TMPDIR"))
return env;
else
return "/tmp";

This is not necessarily the best default for Unix. Most current
Unix implementations use the same hardware partition for the
virtual memory and /tmp. This means that 1) /tmp is typically
pretty small, 2) you are completing with virtual memory to use
it, and 3) accidentally filling it up isn't a very good idea.
Normally, /var/tmp is to be preferred.

Possibly that's something that would vary between platforms and maybe
also between applications (depending on their requirements for
temporary storage space).

Quote:
Also, there is no standard environment variable name for this --
I usually use $TEMP, which wouldn't work with your
implementation.
snip


TMPDIR is specified in the Single Unix Specification
<http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html#tag_08_03>
so while it may be worth checking other variables that should be the
first on the list.

Ben.

--
Ben Hutchings
Having problems with C++ templates? Your questions may be answered by
<http://womble.decadentplace.org.uk/c++/template-faq.html>.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
James Kanze
Guest





PostPosted: Sun Mar 27, 2005 10:25 am    Post subject: Re: temporary functions Reply with quote

Ben Hutchings wrote:
Quote:
kanze (AT) gabi-soft (DOT) fr wrote:

Ben Hutchings wrote:

joel wrote:

I will appreciate it if somebody could give me a good
explanation about difference among temporary functions in
C++/C programming.

tmpnam() is problematic in a multitasking system because
there is a race condition between generation of the filename
and creation of the file, so it is possible to overwrite an
existing file rather than creating a new one.

snip

Finally, if it selects a common temporary directory, such as
/tmp on Unix, the race condition becomes a security flaw. I
strongly recommend you avoid using it.

I'm not sure I see the security flaw unless you get sloppy about
creating the file. Under Unix, for example, using
open( name, O_RW | O_CREAT | O_EXCL, 0x600 )
should be about as secure as you can get, and I'd be surprised
if Windows didn't have similar options.

Sure, but if you're going to have to use non-standard
functions why bother using tmpnam() to generate the name?

Putting it that way: since you're going to have to use
non-standard functions (e.g. for sockets, threading,
windowing...), why bother with any of the standard library.
Using a standard function means one less thing you have to
port. In this case, it also means allowing the system to put
the temporary file where it wants (which is an advantage for
truly temporary files).

Quote:
Of course, this means you need to use the usual extension
(which should be present in any quality implementation where
it makes sense) to initialize a filebuf with a system level
file descriptor.

And of course, the security risk depends largely on what the
program is doing. In something like a compiler, I wouldn't
worry about it.

The risk is not just information leakage but also denial of
service. If the temporary files are being created by a
process running as root, carefully timed creation of a
symbolic link pointing to /dev/kmem might have some
interesting results. If they are being created by an ordinary
user then any of their files with predictable names could also
be overwritten.

If the intruder has access to your machine, can create files
with arbitrary pathnames on it, and run arbitrary programs on
it, you have a serious security problem. Regardless of how you
name your temporary files.

In practice, in most circumstances, if the name is not
predictable (and it shouldn't be), and other users cannot
predict either when the file will be created, then you are
probably safe enough. Obviously, if the program in question
runs as root, more precautions are necessary, but most programs
don't (or shouldn't) run as root.

When security is involved, there are always a number of issues
to be considered; the pros and cons of tmpnam are just the tip
of the iceberg, and hardly worth mentionning.

Quote:
snip

I don't believe there is a good secure way of creating
temporary files that is also portable.

Only because filebuf (and fopen) don't allow access to all of
the necessary underlying flags for the system level open.

Right. It would be useful to be able to specify such flags,
but perhaps not every filesystem implementation supports them.
(Actually I know NFS doesn't support O_EXCL before version 3,
and NFS clients just fudge it rather than failing the call.)

Of course, when security is an issue, you don't put critical
files on a remotely mounted system. Today, when most processors
have a fairly large local disk, it's also fairly rare to put
temporaries on a remote file system.

Quote:
snip

#elif defined(__unix__)
inline string system_temp_dir()
{
if (const char * env = getenv("TMPDIR"))
return env;
else
return "/tmp";

This is not necessarily the best default for Unix. Most
current Unix implementations use the same hardware partition
for the virtual memory and /tmp. This means that 1) /tmp is
typically pretty small, 2) you are completing with virtual
memory to use it, and 3) accidentally filling it up isn't a
very good idea. Normally, /var/tmp is to be preferred.

Possibly that's something that would vary between platforms
and maybe also between applications (depending on their
requirements for temporary storage space).

Right. And presumably, the implementation of tmpnam will vary
to correspond to whatever is appropriate locally. You asked why
use a standard function, above; there's part of the answer.

Quote:
Also, there is no standard environment variable name for this
-- I usually use $TEMP, which wouldn't work with your
implementation.

snip

TMPDIR is specified in the Single Unix Specification

http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html#tag_08_03
so while it may be worth checking other variables that should
be the first on the list.

Good point. I wasn't aware of this; my current code derives
from the code I wrote when I did an implementation of the C
standard library, many, many years ago. I'll change my
implementation (although in so far as I'm not writing a standard
function, I really think that I should change the interface, to
allow the client to specify a preferred directory in the case
where he will later rename the file).

--
James Kanze mailto: [email]james.kanze (AT) free (DOT) fr[/email]
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 pl. Pierre Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Charles Peterson
Guest





PostPosted: Wed Apr 06, 2005 8:51 pm    Post subject: Re: temporary functions Reply with quote

For years I've normally been able to bypass the problems unsolved by
the temporary naming functions by just creating my OWN temporary names.
Typically I use a root named after the calling function, then add the
PID, then add the nodename (from 'uname -n'). The nodename is
important because you could be running in a NFS directory which is a
working directory from several different machines, and while you CAN'T
have multiple processes with the same PID on one node, that could very
well happen with several nodes. Doing this from Tcl (where I like to
program when I can) the name string looks like:

procname.[exec uname -n].[exec pid]

Of course I'm limited to using this within the proc, but that is good
practice anyway (file is opened and closed within the same proc).

I've never had to worry about threads (we'd be in a whole lotta trouble
if there were multithreading) but I see now that if I did I'd simply
have to append the thread ID (from thread_self()) if I did. (I'd have
to create a Tcl command in C to get that, I think.)

Anyway, now I'm back in C for a special job, and it looks to my like I
still want to bypass this whole temporary naming thing again. One
funny thing, the Sun manpages suggest you use tmpfile instead of
mkstemp, whereas the Gnu/linux manpages suggest you use mkstemp and gcc
gives you a stern warning if you use tmpnam/tempnam and suggest you use
mkstemp instead. (And I don't want to use tmpfile anyway...I want the
name for use in a system() call.)

My fallback position for today is to forget system() and rely on a
system() clone I wrote in 1995 (still in constant use here, but it
scares me to look at it today, so I don't think I want to pass it out)
which returns a FILE pointer to the output stream. It's based on
execvp, with lots of other scary system like fork, dup, wait, and
sigaction. There must be something standard that does this, but I
didn't know about it when I wrote this. Besides, writing stuff like
that seemed fun at the time. I used to like the thrill of getting very
close to the bare metal. The only complication that's cropped up over
the years was that I made it convenient for me by using SA_NOCLDWAIT,
but some systems didn't actually support SA_NOCLDWAIT as documented
(DEC Alpha in it's middle years comes to mind) so I had to make that
part conditional and do a wait() on those systems. Before I fixed that
one, a gazillion zombie processes appeared on those obsolescent
systems. Can anyone tell me of a nice C or C++ function that does
something like this?

Charles Peterson


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
kanze@gabi-soft.fr
Guest





PostPosted: Thu Apr 07, 2005 3:02 pm    Post subject: Re: temporary functions Reply with quote

Charles Peterson wrote:
Quote:
For years I've normally been able to bypass the problems
unsolved by the temporary naming functions by just creating my
OWN temporary names.

Typically I use a root named after the calling function, then
add the PID, then add the nodename (from 'uname -n'). The
nodename is important because you could be running in a NFS
directory which is a working directory from several different
machines, and while you CAN'T have multiple processes with the
same PID on one node, that could very well happen with several
nodes. Doing this from Tcl (where I like to program when I
can) the name string looks like:

procname.[exec uname -n].[exec pid]

Of course I'm limited to using this within the proc, but that
is good practice anyway (file is opened and closed within the
same proc).

I've never had to worry about threads (we'd be in a whole
lotta trouble if there were multithreading) but I see now that
if I did I'd simply have to append the thread ID (from
thread_self()) if I did. (I'd have to create a Tcl command in
C to get that, I think.)

All of this should be taken care of by a quality implementation
of tmpnam. You shouldn't have to worry about it. In addition,
a good implementation of tmpnam will ensure that the name is
such that the files will be removed in some sort of regular
system clean-up (reboot or something), either by putting them in
a special directory which gets cleaned out, or by using some
other naming convention. A useful feature if the system crashes
just after you create the file.

Quote:
Anyway, now I'm back in C for a special job, and it looks to
my like I still want to bypass this whole temporary naming
thing again. One funny thing, the Sun manpages suggest you use
tmpfile instead of mkstemp, whereas the Gnu/linux manpages
suggest you use mkstemp and gcc gives you a stern warning if
you use tmpnam/tempnam and suggest you use mkstemp instead.
(And I don't want to use tmpfile anyway...I want the name for
use in a system() call.)

Don't blame gcc for this one (I think). G++ under Solaris
doesn't complain, and tmpnam is part of libc, which is normally
provided by the system, and not by g++. The problem is more
likely Linux.

Quote:
My fallback position for today is to forget system() and rely
on a system() clone I wrote in 1995 (still in constant use
here, but it scares me to look at it today, so I don't think I
want to pass it out) which returns a FILE pointer to the
output stream. It's based on execvp, with lots of other scary
system like fork, dup, wait, and sigaction. There must be
something standard that does this, but I didn't know about it
when I wrote this. Besides, writing stuff like that seemed fun
at the time. I used to like the thrill of getting very close
to the bare metal. The only complication that's cropped up
over the years was that I made it convenient for me by using
SA_NOCLDWAIT, but some systems didn't actually support
SA_NOCLDWAIT as documented (DEC Alpha in it's middle years
comes to mind) so I had to make that part conditional and do a
wait() on those systems. Before I fixed that one, a gazillion
zombie processes appeared on those obsolescent systems. Can
anyone tell me of a nice C or C++ function that does something
like this?

Nothing in C or C++ per se, but if you are on a Unix system, and
want to write or read from a child process, letting the process
run in parallel with whatever you are doing, the Posix function
popen would seem exactly what is needed. (It's been more or
less standard Unix for as long as I can remember.)

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.