首页 > 解决方案 > 如何“cd”到显示“权限被拒绝”的符号链接目录?

问题描述

我目前在我的 Linux 操作系统上有两个用户,用于两个不同的 DE。但是,我想尽可能地消除帐户之间的文件重复性。具体来说,我一直在尝试将~/german-capstone文件夹从用户链接segeeslicelucifer.

为此lucifer,我打电话给:

ln -s /home/segeeslice/german-capstone /home/lucifer/

它按预期运行,将链接放在正确的位置。但是,尝试访问它会引发如下错误:

bash: cd: german-capstone: Permission denied


我知道这可能只是一个权限问题,但我找不到来源!我已经尽可能让双方完全访问该文件夹及其内容,但似乎没有任何效果。我错过了什么?

这里源目录的权限
这里符号链接的权限


作为对评论的回应,以下是完整的权限列表:

------ /home/lucifer/german-capstone ------

    drwxr-xr-x  755 root     root     /
    drwxr-xr-x  755 root     root     /home
    drwxr--r--  744 lucifer  lucifer  /home/lucifer
    lrwxrwxrwx  777 lucifer  lucifer  /home/lucifer/german-capstone
                                      -> /home/segeeslice/german-capstone
    drwxr--r--  744 segeeslice segeeslice /home/segeeslice
    drwxrwxrwx  777 segeeslice segeeslice /home/segeeslice/german-capstone

更高级别仍然具有正确的读取属性...我需要在某处授予更多权限吗?

标签: linuxpermissionssymlink

解决方案


它可能是源目录或符号链接路径上任何位置的权限,还包括在这些东西的路径中遇到的任何其他符号链接。

这是一个脚本,它将为您显示所有这些权限。它将显示从根目录到相关路径的所有内容的权限,如果遇到符号链接,它将根据链接目标重新启动,除了它不会重复它拥有的任何目录的输出已经向您展示了(例如,权限/仅显示一次)。

#!/usr/bin/perl
#
use strict;


my $usage=<<EOF;
Usage: $0 file [file ...]

 Shows permissions on every path component from root directory to the named
 file(s), including paths traversed while following symlinks.

 Also shows permissions and contents of any .ftpaccess or .htaccess files
 encountered.

 If multiple files are specified, gives a listing for them all, but for later
 files does not show again the permissions on a path component already shown
 for earlier files.

EOF
#----------------------------------------------------------------------

use Cwd;
my $cwd = cwd;
chomp $cwd;

if ($#ARGV==-1) {
    print $usage;
    exit 1;
};

my @history=();
my @accessfiles=();

# loop over files on command line.
FILE: foreach my $fullpath (@ARGV) {

    # prepend cwd if relative path
    $fullpath="$cwd/$fullpath" unless $fullpath =~ /^\//;

    # fix pathname..
    $fullpath=stripslashes($fullpath);

    print "\n------ $fullpath ------\n\n";

    my $len=length $fullpath;
    my $pos=-1;
    my @targets=($fullpath);

    ELEMENT: while ($pos<$len) {

    # get full pathname of next element (etc)

    my $stem=($pos>=0) ? substr($fullpath,0,$pos) : ''; # parent

    $pos=index($fullpath,'/',$pos+1);
    $pos=$len if $pos==-1;
    my $path=($pos>0) ? substr($fullpath,0,$pos) : '/';

    my $remainder=substr($fullpath,$pos);

    #
    # stat the path element.
    #
    my @stat=lstat($path);
    my $okay=($#stat != -1);

    # tidy up as follows:
    #   if trailing "/foo/.." or "/." strip it and move to next element.
    #
    # We can do this because at this stage "foo" isn't a link,
    #  or we would already have followed it, but only do it if stat
    #  succeeded as parent might not be a directory (in that case, the
    #  error trap later will be executed).
    #
    my ($newpath, $subst);
    if ($okay) {
        $subst=1;   
        if ( $path =~ /\.\.$/ ) {       
        if ($stem eq '') {
            $newpath='/';
            $fullpath=$remainder;
        } else {
            ($newpath = $stem) =~ s,/([^/]*?)$,, ;
            $fullpath=$newpath.$remainder;
            if ($newpath eq '') {$newpath='/';}
        }
        }
        elsif ( $path =~ /\.$/ ) {
        if ($stem eq '') {
            $newpath='/';
            $fullpath=$remainder;
        } else {
            $newpath = $stem;
            $fullpath=$newpath.$remainder;
        }
        }
        else {
        $subst=0;
        }
        if ($subst) {
        $path=$newpath;
        $pos=length $path;
        $len=length $fullpath;
        next ELEMENT;
        }
    }

    # have we been here before?
    my $beenthere=grep {$_ eq $path} @history;
    push @history,$path;

    # is it a symlink?
    if (-l _) {

        # yes. see where it points
        my $pointsto=readlink $path;
        my $newfile;
        if ($pointsto =~ /^\//) {
        # link is absolute pathname
        $newfile=$pointsto.substr($fullpath,$pos);
        $pos=-1;
        } else {
        # link is relative pathname
        $newfile=$stem.'/'.$pointsto.substr($fullpath,$pos);
        $pos=length $stem;
        }
        if (!$beenthere) {
        show_stat(\@stat,$path,$pointsto);
        }
        # strip extra "/"
        $newfile=stripslashes($newfile);

        # check for recursive links
        my $beenthere2=grep {$_ eq $newfile} @targets;
        push @targets,$newfile;
        if ($beenthere2) {
        print " === SYMLINK LOOP DETECTED ===\n";
        next FILE;
        }
        # follow the link (stripping extra "/"s)
        $fullpath=$newfile;
        $len=length $fullpath;
    } else {
        # no, not a symlink
        # print info, with usernames/groupnames where possible
        # unless we've been here before...
        if (!$beenthere) {
        if (! $okay) {
            print "\n*** ERROR : $path : $! ***\n";
            next FILE;
        }
        show_stat(\@stat,$path);

        #
        # check for any {.htaccess,.ftpaccess} files
        # 
        for my $name (qw(.htaccess .ftpaccess)) {
            my $file = "$path/$name";
            if (-e $file) {
            push @accessfiles,$file;
            }
        }
        }       
    }
    } # end ELEMENT loop
} # end FILE loop
continue {    
    print "\n";
}

if ($#accessfiles > -1) {
    print "Access control files of possible relevance:\n\n";
    for my $file (@accessfiles) {
    my @stat = stat($file);
    show_stat(\@stat,$file);
    if (open my $access,$file) {
        print "\n    ---- Contents of $file ----\n";
        while (defined (my $line=<$access>)){
        chomp $line;
        print "    $line\n";
        }
        close $access;
        print "    ------- End of $file -------\n";
    } else {
        print "    Could not open $file: $!\n";
    }
    }
    print "\n";
}

exit 0;

#-------------------------------------------------------------
sub stripslashes 
{    
    my $line = shift;

    # strip trailing or repeated '/'s
    $line =~ s,/*$,,;
    $line =~ s,//+,/,g;
    $line =~ s,^$,/,;

    return $line;
}

sub show_stat
{
    use Fcntl ':mode';

    my ($stat,$path,$linktarget) = @_;

    my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
    $atime,$mtime,$ctime,$blksize,$blocks) = @$stat;


    my @pwent=getpwuid($uid);
    my $username=($#pwent == -1) ? "($uid)" : $pwent[0];
    my @grent=getgrgid($gid);
    my $grpname=($#grent == -1) ? "($gid)" : $grent[0];
    printf ("%s %4o %-8s %-8s %s\n",
        symbolic_mode($mode),
        $mode&07777,$username,$grpname,$path);

    if (S_ISLNK($mode) and defined($linktarget)) {
    print "                                  -> $linktarget\n";
    }

}

sub symbolic_mode
{
    # takes a numerical mode returned by stat,
    # returns a symbolic string as per "ls -l"
    # e.g. for 0640 returns "-rw-r-----"

    my $mode = shift;

    use Fcntl ':mode';

    my $typechar = 
    S_ISREG($mode) ? '-' :
    S_ISDIR($mode) ? 'd' :
    S_ISLNK($mode) ? 'l' :
    S_ISBLK($mode) ? 'b' :
    S_ISCHR($mode) ? 'c' :
    S_ISFIFO($mode) ? 'p' :
    S_ISSOCK($mode) ? 's' : 
    '?';

    my $modestr = $typechar . 'rwxrwxrwx';
    for (my $bit=0; $bit <= 8 ; $bit++) {
    if (($mode & (1<<$bit)) == 0) {
        substchar(\$modestr,9-$bit,"-");
    }
    }
    if ($mode & 01000) {
    substchar(\$modestr,9,
          ($mode & 0001) ? "t" : "T");
    }
    if ($mode & 02000) {
    substchar(\$modestr,6,
          ($mode & 0010) ? "s" : "S");
    }
    if ($mode & 04000) {
    substchar(\$modestr,3,
          ($mode & 0100) ? "s" : "S");
    }    
    return $modestr;
}

sub substchar
{
    # substitutes a character in a string
    my ($sref, $pos, $newchar) = @_;
    my $string = $$sref;
    my $newstring = substr($string,0,$pos) . $newchar . substr($string,$pos+1);
    $$sref=$newstring;
}

示例输出:

$ mkdir -p /tmp/mydir/stuff
$ ln -s stuff /tmp/mydir/stuff2
$ cal > /tmp/mydir/stuff2/myfile
$ mkdir /tmp/mydir2
$ ls /tmp/mydir2/stuff2/myfile
ls: cannot access '/tmp/mydir2/stuff2/myfile': No such file or directory
$ ls /tmp/mydir/stuff2/
myfile
$ ln -s /tmp/mydir/stuff2/myfile  /tmp/mydir/stuff2/thingy
$ chmod 700 /tmp/mydir
$ permsto  /tmp/mydir/stuff2/thingy

------ /tmp/mydir/stuff2/thingy ------

drwxr-xr-x  755 root     root     /
drwxrwxrwt 1777 root     root     /tmp
drwx------  700 myuser   mygroup  /tmp/mydir
lrwxrwxrwx  777 myuser   mygroup  /tmp/mydir/stuff2
                                  -> stuff
drwxr-xr-x  755 myuser   mygroup  /tmp/mydir/stuff
lrwxrwxrwx  777 myuser   mygroup  /tmp/mydir/stuff/thingy
                                  -> /tmp/mydir/stuff2/myfile
-rw-r--r--  644 myuser   mygroup  /tmp/mydir/stuff/myfile

因此,您可以查看输出并一目了然地看到任何权限问题潜伏在哪里。


现在问题已更新为包含相关目录中脚本的输出,很明显问题出在以下目录的权限上:

    drwxr--r--  744 lucifer  lucifer  /home/lucifer
    drwxr--r--  744 segeeslice segeeslice /home/segeeslice

如果进程已读取但不执行对目录的访问,它将能够列出目录但不能访问其中包含的任何路径。对于具有八进制模式 744 的目录,任何不以所有者(或 root)身份运行的进程都是这种情况,这将依赖于“组”或“其他”权限。如果将其更改为八进制模式 755(即为“组”和“其他”添加执行权限),那么这些将具有必要的访问权限。


推荐阅读