LinuxQuestions.org
Latest LQ Deal: Latest LQ Deals
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 08-13-2011, 08:26 PM   #1
benav
Member
 
Registered: Sep 2009
Location: Canada
Distribution: Slackware 14.0
Posts: 36

Rep: Reputation: 1
Generating a temporary file name in C


I'm tired of gcc complaining about my use of tempnam(), so I'd like to find an alternative. However, I need a function that returns a file name, not a file stream, and that doesn't open the file yet. I want to pass the file name to an external editor for input. Can anybody suggest a way of accomplishing this?

I currently have the editor command concatenated with the return from tempnam (), so it ends up something like "vim /tmp/strinXXXXXX", which I can later call with "system (editor_command)". It works just fine, exactly the way I want it to; I just want gcc to quit whining about the fact that tempnam is insecure. (Especially since if I call ':make' from within vim, it gives me the warning and then when I return to the editor it jumps to the line with the tempnam function, which is not where I was working.)
 
Old 08-13-2011, 10:05 PM   #2
dwhitney67
Senior Member
 
Registered: Jun 2006
Location: Maryland
Distribution: Kubuntu, Fedora, RHEL
Posts: 1,541

Rep: Reputation: 335Reputation: 335Reputation: 335Reputation: 335
I suggest you stop using tempnam() as the compiler suggests; it has been deprecated (per POSIX.1-2008). Use mkstemp() instead. You can always close the file immediately after it is opened so that you can then use the filename with your preferred application (editor).

Here's a simple example:
Code:
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>

int main()
{
   char filename[] = "TemporaryXXXXXX";

   int fd = mkstemp(filename);
   close(fd);

   printf("filename = %s\n", filename);

   /* ... */

   return 0;
}
 
Old 08-14-2011, 05:14 AM   #3
benav
Member
 
Registered: Sep 2009
Location: Canada
Distribution: Slackware 14.0
Posts: 36

Original Poster
Rep: Reputation: 1
Quote:
Originally Posted by dwhitney67 View Post
char filename[] = "TemporaryXXXXXX";

int fd = mkstemp(filename);
close(fd);

printf("filename = %s\n", filename);
[/code]
So, I have to generate a unique filename myself and make sure it doesn't already exist. How is that more secure than having tempnam do it, given that the security complaint about tempnam is that between the time the file name is generated and the time it is opened, the same name could be generated by another application?
 
Old 08-14-2011, 05:47 AM   #4
Proud
Senior Member
 
Registered: Dec 2002
Location: England
Distribution: Used to use Mandrake/Mandriva
Posts: 2,794

Rep: Reputation: 116Reputation: 116
Firstly, read the man page like I should have done first, mkstemp takes a template, the Xs are literally Xs, you don't have to make the unique name.
Quote:
The last six characters of template must be XXXXXX and these are replaced with a string that makes the filename unique... Since it will be modified, template must not be a string constant, but should be declared as a character array.
As for security:
Huh? Security is through users and fileystem permissions, not obfuscated/pseudorandom filenames, no?
If you make the tempfile first, you own it, right? Deny them writing to it before you put contents in it. Edit: seems most systems will create mkstemp tempfiles with 0600.
If they make it first, you can't write to it/can't change it's permissions (or you can because you and this malicious other app are running under the same account which is a user's problem, or they're root and you can't win anyway).
Edit: Again from mkstemp
Quote:
The file is opened with the open(2) O_EXCL flag, guaranteeing that when mkstemp() returns successfully we are the only user.
Also, encrypt contents if it's so important, and don't write the decryption key out, and trust that memory isn't being read?

Last edited by Proud; 08-14-2011 at 05:54 AM.
 
Old 08-14-2011, 06:18 AM   #5
benav
Member
 
Registered: Sep 2009
Location: Canada
Distribution: Slackware 14.0
Posts: 36

Original Poster
Rep: Reputation: 1
Quote:
Originally Posted by Proud View Post
As for security:
Huh? Security is through users and fileystem permissions, not obfuscated/pseudorandom filenames, no?
If you make the tempfile first, you own it, right? Deny them writing to it before you put contents in it. Edit: seems most systems will create mkstemp tempfiles with 0600.
If they make it first, you can't write to it/can't change it's permissions (or you can because you and this malicious other app are running under the same account which is a user's problem, or they're root and you can't win anyway).
Edit: Again from mkstemp
Also, encrypt contents if it's so important, and don't write the decryption key out, and trust that memory isn't being read?
It's not an issue to me; I just want gcc to shut up about it. From GNU's libc manual (http://www.gnu.org/s/hello/manual/li...ary-Files.html):
Quote:
Warning: Between the time the pathname is constructed and the file is created another process might have created a file with the same name using tmpnam, leading to a possible security hole. The implementation generates names which can hardly be predicted, but when opening the file you should use the O_EXCL flag. Using tmpfile or mkstemp is a safe way to avoid this problem.
 
Old 08-14-2011, 06:22 AM   #6
benav
Member
 
Registered: Sep 2009
Location: Canada
Distribution: Slackware 14.0
Posts: 36

Original Poster
Rep: Reputation: 1
Quote:
Originally Posted by Proud View Post
Firstly, read the man page like I should have done first, mkstemp takes a template, the Xs are literally Xs, you don't have to make the unique name.
Ah. I missed the part about mkstemp actually replacing the X's.
 
Old 08-14-2011, 09:27 AM   #7
TimothyEBaldwin
Member
 
Registered: Mar 2009
Posts: 249

Rep: Reputation: 27
Quote:
Originally Posted by Proud View Post
If you make the tempfile first, you own it, right? Deny them writing to it before you put contents in it. Edit: seems most systems will create mkstemp tempfiles with 0600.
If they make it first, you can't write to it/can't change it's permissions
But if they put a link to one of your files first, and you don't pass O_EXCL to open, then you will write to your existing file.
 
Old 08-14-2011, 12:08 PM   #8
benav
Member
 
Registered: Sep 2009
Location: Canada
Distribution: Slackware 14.0
Posts: 36

Original Poster
Rep: Reputation: 1
Quote:
Originally Posted by dwhitney67 View Post
I suggest you stop using tempnam() as the compiler suggests; it has been deprecated (per POSIX.1-2008). Use mkstemp() instead. You can always close the file immediately after it is opened so that you can then use the filename with your preferred application (editor).

Here's a simple example:
Code:
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>

int main()
{
   char filename[] = "TemporaryXXXXXX";

   int fd = mkstemp(filename);
   close(fd);

   printf("filename = %s\n", filename);

   /* ... */

   return 0;
}
So mkstemp returns an int. I was using fopen(), as prescribed in all the file I/O tutorials I've seen, later on to read from this temporary file, but it wants a FILE* struct. Do I now have to use something else?

Edit: Never mind, I got confused about which variable I had to pass where for what reason.

Last edited by benav; 08-14-2011 at 12:12 PM. Reason: Brain not working.
 
Old 08-14-2011, 01:00 PM   #9
Nominal Animal
Senior Member
 
Registered: Dec 2010
Location: Finland
Distribution: Xubuntu, CentOS, LFS
Posts: 1,723
Blog Entries: 3

Rep: Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948
Quote:
Originally Posted by benav View Post
So mkstemp returns an int.
It returns a file descriptor you can "convert" to FILE* using fdopen(). You could use something like this:
Code:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

/* Create a file with an unique name, beginning with the specified prefix.
 *
 * The file name will be dynamically allocated, and saved in the pointer
 * pointed by nameptr. After you are done with the file, you should
 * release the dynamically allocated name using free().
 *
 * If you supply NULL nameptr, the file will be immediately unlinked,
 * and the dynamically allocated file name freed. Thus, the file will not
 * have a name (except for a brief moment within this function).
 * (In this case, the function is similar to tmpfile(), except that this
 *  function lets you specify the prefix or directory for the file.)
 *
 * If an error occurs, the function will return NULL with errno set.
 *
 * Example:
 *
 *	FILE *filehandle;
 *	char *filename;
 *
 *	filehandle = fopen_unique("/tmp/my-prefix.", &filename);
 *	if (!filehandle) {
 *
 *		error, check errno [/I]for reason[/I]
 *
 *	} else {
 *
 *		work on the file
 *
 *		fclose(filehandle);
 *		remove(filename);
 *		free(filename);
 *	}
*/
FILE *fopen_unique(char const *const prefix, char **nameptr)
{
	size_t const	 n = (prefix) ? strlen(prefix) : 0;
	char		*name;
	FILE		*handle;
	int		 descriptor, result, saved_errno;

	if (n < (size_t)1) {
		errno = EINVAL;
		return NULL;
	}

	name = malloc(n + 7);
	if (!name) {
		errno = ENOMEM;
		return NULL;
	}
	memcpy(name, prefix, n);
	name[n+0] = 'X';
	name[n+1] = 'X';
	name[n+2] = 'X';
	name[n+3] = 'X';
	name[n+4] = 'X';
	name[n+5] = 'X';
	name[n+6] = 0;

	do {
		descriptor = mkstemp(name);
	} while (descriptor == -1 && errno == EINTR);
	if (descriptor == -1) {
		saved_errno = errno;
		free(name);
		errno = saved_errno;
		return NULL;
	}

	if (!nameptr) {
		do {
			result = unlink(name);
		} while (result == -1 && errno == EINTR);
		if (result == -1) {
			saved_errno = errno;
			close(descriptor);
			free(name);
			errno = saved_errno;
			return NULL;
		}
		free(name);
		name = NULL;
	} else {
		*nameptr = name;
	}

	do {
		handle = fdopen(descriptor, "r+");
	} while (handle == NULL && errno == EINTR);
	if (!handle) {
		saved_errno = errno;
		if (name) {
			unlink(name);
			free(name);
		}
		close(descriptor);
		errno = saved_errno;
		return NULL;
	}

	return handle;
}
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
temporary cifs file kellemes Linux - Networking 2 07-03-2009 07:00 AM
copy last 10000+ lines of large text file to a temporary file emilyg Linux - Newbie 3 06-24-2009 02:43 PM
How to stop emacs from generating the ~ temporary file? silentray Linux - Newbie 1 11-20-2008 05:30 PM
pwmconfig Cannot create temporary file?!? dangerousdave Linux - Software 1 05-01-2006 07:27 PM
Installing a temporary(?) file natedogver31 Linux - Newbie 14 04-02-2004 05:05 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 02:57 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration