Re: Avoiding race conditions
by KM (Priest) on Apr 24, 2001 at 20:57 UTC
|
I have a calendaring system which I tinker with from time to time and I make PDF reports of schedules and such. What I did was make the text into a POD format, then use POD::Pdf (well, a hacked up version). But, that may not fit your needs :) I have used some other PDF tooks in the past and suggest trying a few to see what is best for your app.
As for the filenames. Is the 'user' actually logged in (via some way you have an equiv of REMOTE_USER)? I have used things like $ENV{REMOTE_USER}.$$.file.ext for simple anti-race names. I also use the following to generate a random name:
my @set = ('a' .. 'z', 'A' .. 'Z');
my $length = 8; # Change length if desired
my $random = join "" => map {$set [rand @set]} 1 .. $length;
my $tmp_file = $random . "." . $$ . ".ext";
Many people have their own way to get a unique name. I tend to like adding a login name (if available), the PID (assuming I will unlink() the file when done), and some random string. If you are extra paranoid (or extra careful :) you could also add a sempahore file with the name of your temp file, and lock it. If you can't get a lock on it, then the name must be in use and you can generate another.
Cheers,
KM | [reply] [d/l] |
|
|
- POD::Pdf:
- My data is in two column table format, so I don't think POD will pull it off, but I'll give it a glance anyway. Does POD support pagebreaks?
- Unique features:
- No, sadly the user is not logged in. This isn't mod_perl, just straight CGI, so I could use the PID I suppose. hmm. Other than a cronjob, I have no idea how to automatically unlink the file, since the CGI creating the PDF will end presumably long before the PDF is completely downloaded.
| [reply] |
|
|
My data is in two column table format, so I don't think POD will pull it off, but I'll give it a glance anyway. Does POD support pagebreaks?
Yeah, I would experiment with other POD::*, or a *2pdf utility. POD doesn't do pagebreaks (as far as I have ever read), but the PDF module/utility will give you a way to define the page dimensions.. so it should add pagebreaks.
No, sadly the user is not logged in. This isn't mod_perl, just straight CGI, so I could use the PID I suppose. hmm. Other than a cronjob, I have no idea how to automatically unlink the file, since the CGI creating the PDF will end presumably long before the PDF is completely downloaded.
I do this:
my $out = pod2pdf(@args);
print "Content-Type: application/pdf\n";
print "Content-Disposition: attachment; filename=$username.tasks.pdf\n
+\n";
unlink "./pod/$username.tasks.$$.pod";
binmode(STDOUT);
return print $out;
Of course, YMMV depending on the module you use. I think I had hacked POD::Pdf to return the Pdf data instead of just writing it to the file. I don't recall. But, otherwise you could just read the file in and print it:
my $out;
{
local $/ = undef;
open(PDF, "$file") or die "foo $!";
$out = <PDF>;
close PDF;
}
Or whatever fits your fancy.
Cheers,
KM | [reply] [d/l] [select] |
|
|
Re: Avoiding race conditions
by nardo (Friar) on Apr 24, 2001 at 22:34 UTC
|
You can use File::Temp to return both the filehandle and filename. When this is done, there is no race condition. When File::Temp opens a file, it does so with O_CREAT|O_EXCL set in the flags and a mode of 600, which ensures that the file will be created and only you will be able to read/write to it. A race condition would be to return only the filename and then open() it because the file could have been generated by someone else in between the time of File::Temp checking to see if it exists and you opening it. So, if you use the File::Temp functions in list format ($filehandle, $filename) = tempfile(...) you should be safe (assuming your temp directory isn't on NFS). | [reply] [d/l] |
|
|
That's what I thought, but in the File::Temp documentation:
- WARNING
- For maximum security, endeavour always to avoid ever
looking at, touching, or even imputing the existence of
the filename. You do not know that that filename is
connected to the same file as the handle you have, and
attempts to check this can only trigger more race
conditions. It's far more secure to use the filehandle
alone and dispense with the filename altogether.
| [reply] |
|
|
Yes, that is correct, if the file was made in a directory which is world writeable (like most temp directories) and does not have the sticky bit set (unlike most temp directories) then someone can come along and delete the file and make a new one in its place with the same name. While we're on the subject, one practice, which I consider good form in general (but which may not work for you, since you want the file avaiable via www), is to create a ~/tmp with 700 permissions and create all temp files in there, this prevents all of the /tmp race condition security bugs that have cropped up in the past and will surely crop up in the future (it still does not prevent a race condition, two copies of your program could both generate the same filename before either of them opened it, but it prevents someone from symlinking the file to /etc/passwd or creating and opening it first). Anyways, back to your problem: since you are publishing the files via www, I assume that they are being put in a directory which is writeable only by you, if this is the case then you do not need to worry about anyone deleting the file, people will probably be able to read the file but I don't think that is a big problem since you're making it available via the www and someone could just fetch it via the www rather than the local filesystem if they could predict the filename, though a brute force guess would be much slower via www.
| [reply] |