ftp_abort("invalid internal operation list")
unless $oplist->[0][0] eq 'header';
my $header = $oplist->[0][1];
+ my @directory = File::Spec::Unix->splitdir($header->{directory});
my $destdir = "$Public_dir/$header->{directory}";
foreach my $step (@{$oplist}[1..$#$oplist]) { # skip the header
} elsif ($step->[0] eq 'symlink') {
my $target = $step->[1];
my $linkname = $step->[2];
- # Get current working dir
- my $cwd = getcwd;
- # Make sure there are no double dots in the path, and that it is absolute.
- # A bit paranoid, but hey...
- fatal("invalid directory $cwd",1,'')
- if (($cwd =~ /\.\./) || (!($cwd =~ m,^/,)));
- # Now untaint the getcwd output
- $cwd =~ /^(.*)$/;
- $cwd = $1;
- chomp($cwd);
- # change to destination dir
- chdir($destdir);
+ my $abslinkname =
+ File::Spec->catfile($Public_dir, @directory, $linkname);
# if the symlink already exists, remove it
- if (-l $linkname) {
- unlink $linkname
+ if (-l $abslinkname) {
+ unlink $abslinkname
or fatal("removal of symlink $linkname failed: $!",1);
}
# symlink away!
- symlink $target, $linkname
+ symlink $target, $abslinkname
or fatal("creation of symlink $linkname "
- ."to $target in $destdir failed: $!",1);
- # go back to current working dir
- ftp_syslog('info', "added symlink $destdir/"
- .$linkname . " pointing to $destdir/$target");
- chdir($cwd)
- or fatal("chdir to $cwd failed: $!",1);
+ ."to $target in $header->{directory} failed: $!",1);
+ ftp_syslog('info', "added symlink $linkname pointing to "
+ ."$target in $header->{directory}");
} elsif ($step->[0] eq 'rmsymlink') {
+ my $abslinkname =
+ File::Spec->catfile($Public_dir, @directory, $step->[1]);
fatal("refusing to remove a non-symlink file",1)
- unless -l "$destdir/$step->[1]";
- unlink("$destdir/$step->[1]")
+ unless -l $abslinkname;
+ unlink $abslinkname
or fatal("removal of symlink $step->[1] failed: $!",1);
- ftp_syslog('info', "removed symlink $destdir/$step->[1]");
+ ftp_syslog('info', "removed symlink $step->[1] in $header->{directory}");
} elsif ($step->[0] eq 'archive') {
# We now also allow archiving entire directories
archive($destdir, $header->{directory}, $step->[1].'.sig')