How can I make a write only ftp directory?

My former hosting service had ftp accounts that had a home directory that was readable to the ftp users (444) and a "incoming subdirectory that was write only (222) to the ftp users. This was real handy for me since I could put a RFP in the read directory, send out the ftp user name and password to potential contractors, and have the contractors drop off their proposals in the write only incoming directory. Since the incoming directory was write only, the potential contractors weren’t able to peek at competitors’ bids. How can I do this on DH?

I considered tricks with file permissions on DH, but if I make a ftp user directory write only, how am I ever going to read it without having super user access? Can I do it with some kind of group permission trick? So far my shell users and ftp users all seem to be assigned to the same group.

You can do this with anonymous FTP… our panel lets you assign permissions for different commands to specific directories. Unfortunately, I don’t think this is available as an add-on anymore - it’s only available on plans that support it (Code Warrior, Strictly Business). We don’t do this so much by using regular UNIX file permissions, but rather by using features in our FTP server.

As long as the ftp user is allowed to chmod, I’m reasonably sure that someone could pretty easily just change the permissions and read the stuff in the “write only” directory.

Yes, I saw that the $79.95/mo plan has anonymous FTP and now the $39.95/mo plan has it too, but it’s not worth it to me to jump to the more expensive hosting plans from Sweet Dreams. And I wasn’t sure what I could do with anonymous FTP on DH, but it sounds like there is lots of options.

I didn’t see any was of adding just anonymous FTP to Sweet Dreams as an option.

I was hoping there might be a trick with umask, or the sticky bit, or setgid bit, but it looks like all my user accounts belong to the same group.

Even if you set the permissions a particular way, though, you have the issue of someone logging in and resetting the permissions. You might be able to do something like create two users (one shell/ftp user for you, and one ftp only-user for uploads downloads), and put one inside the other; then set the permissions something like (totally untested):

rwx-wx--- user ftpgroup incoming
(where ftpgroup is the special group you’ve created for this)
and then an incoming directory with permissions something like this

rwxr-x--- user ftpgroup dropbox
If you play around with this a little, you may be able to get it to work.

Yes, but can I create and manage groups from a user shell?

To keep someone from mving or cping the file – that’s what the sticky bit is for. Does this system have sticky bits? I 'll have to get in a shell and try a few things.

No, but you can from the web panel.

Yes, but the sticky bit just keeps someone from moving or renaming files they don’t own, and any files created by the ftp user would be owned by that user.

Great idea. Do you know of a simple example in Perl to get me started?

See the documentation for the CGI module for further help.

[code]use CGI;
use CGI::Carp qw(fatalsToBrowser);
use File::Copy;

get value of INPUT field

my $filename = $CGI->param(‘filename’);

remove the drive and path if provided (Internet Explorer)

$filename =~ s/.*\//g;

convert whitespace to underscore

$filename =~ s/\s+/_/g;

directory to store files in, no trailing slash

my $path = “/home/username/domain”

full path and filename

my $file = “$path/$filename”;

copy temporary file to where it should go

if (length $filename > 0) {
my $fh = $CGI->upload(‘filename’);
seek($fh, 0, 0);
if (copy($fh, $file) > 0) {
truncate($fh, 0);

[/code] :cool: Perl / MySQL / HTML+CSS

I think I’m getting this script close to running, but nothing shows up in my uploads directory wether I put it at ~/uploads and ~/ I tried many syntaxes for $upath and $uindex. Should I ask over on the Programming forum area?


Virtual Webwerx Form-Based Upload CGI

v1.0 (17 Feb 96) by James K. Boutcher (

Feel free to use, modify, distribute… But remember to give some credit

where credit is due.

If you are having problems with this, or have a bug to report, just send

me some mail

Let’s define our variables first off…

$| = 1;
$upath = “~/”;
$uindex = “~/”;
$tempfile = $upath . $ENV{‘REMOTE_ADDR’};
$nofileerror = “”;

The following reads in the CGI buffer, and writes it to a temporary file

which will used later.

read(STDIN, $buffer, $ENV{‘CONTENT_LENGTH’});
open (x,">$tempfile");
print x $buffer;
close (x);

Now, time to open the temporary file and process it!

open (temp,$tempfile);

Gotta pull the MIME/multipart separator line out… We’ll keep the 15

digit number for later…

$_ = ;
($vernum) = /(\d+)/;

Next line of the file contains the filename in the format:


We’ll just keep the part inside the quotes…

$_ = ;
$filetemp = $1 if (/filename="(.*)"/);

The filename currently has the full pathname to the file in it… We

don’t want that! … First we grab the last word after the backslash (for

PC systems), then we’re gunna grab the last word after the forward slash

(unix systems)… Don’t worry, it works.

@pathz = (split(/\/,$filetemp));
$filetempb = $pathz[$#pathz];
@pathza = (split(’/’,$filetempb));
$filename = $pathza[$#pathza];

And, if the filename is nothing, we’ll clean everything up and give them

a pretty error message

if ($filename eq “”) {
print “Location: $nofileerror\n\n”;
rm $tempfile;

Now that we know the name of the file, let’s create it in our upload


open (outfile, “>$upath$filename”);

Now we don’t care about the Content-type of this, so we’ll pass that up

$junk = ;
$junk = ;

And we’re gunna read/write all the lines of our file until we come to the

MIME-multipart separator, which we’ll ignore.

while () {
if (!(/-{28,29}$vernum/)) {
print outfile $_;

We’re done with that… Let’s close things up and remove that temp file.

close (temp);
close (outfile);
rm $tempfile;

And bust da HTML

print “Content-type: text/html\n\n”;
print “Form Upload\n”;
print “

Thank You!

Your file, $filename, \n”;
print "has been successfully transferred to this site.

print “<a href=”~/">And, for you non-believers out there…
print “”;

Yeah, well I’m not even going to try to debug that, but I did notice theres no error checking, you might want to throw that in :stuck_out_tongue:

Though if I were you, I’d stick with my example for file uploads. The CGI module is capable of handling more than one file and as you can see all you need is to copy from a temporary file handle to where you want it to go.

For error checking -use CGI::Carp qw(fatalsToBrowser);- if an runtime error occurs the web page is the error message instead of server error

if (open(filehandle, $file)) { } else { die("unable to open $file - $!"); }- tells you why a file wasn’t created

Tell you what, I’ll re-write my example to match the functionality of the script you’re trying to use, and post it in the Programming section.

:cool: Perl / MySQL / HTML CSS