X $ARGV[$FIRST] =~ /^-g/ && ($do_world++,$do_group++, $do_user = 0,shift(@ARGV),next);
X# -u flag
X $ARGV[$FIRST] =~ /^-u/ && ($do_world++,$do_group++, $do_user++,shift(@ARGV),next);
X last;
X
X }
X}
Xsub main {
X &getusers();
X &getgroups();
X &dotrojans();
X}
Xsub dotrojans {
X &checkrootdir();
X @dirs = split(/:/,$ENV{'PATH'});
X foreach $dir (@dirs) {
X $debug && $verbose && printf("%s: \n",$dir);
X $reason = "$dir is in your searchpath";
X if ($dir eq ".") {
X $dot++;
X $dir = `pwd`;
X chop $dir;
X }
X if ( -l $dir) {
X $link = readlink($dir);
X $debug && printf("$dir points to $link\n");
X $reason .= " AND $dir -> $link";
X if ($link !~ /^\// ) {
X # a relative link
X $link = &resolve($dir,$link);
X $reason .= " ($link) ";
X }
X &checkupdir($link,$reason,$SEARCHPATH);
X while ( -l $link ) {
X $oldlink = $link;
X $link = readlink($oldlink); #
X if ($link !~ /^\// ) {
X # a relative link
X $newlink = &resolve($dir,$link);
X $reason .= " ($newlink) ";
X }
X $reason .= "$oldlink -> $link AND";
X &checkupdir($link,$reason,$SEARCHPATH);
X }
X if ( -d $link ) {
X &checkdir($link, $reason);
X &checkupdir($link,$reason,$SEARCHPATH);
X &checkexecsindir($link, $reason);
X
X
X }
X } elsif ( -d $dir ) {
X &checkdir($dir, $reason);
X &checkupdir($dir,$reason,$SEARCHPATH);
X &checkexecsindir($dir, $reason);
X }
X
X }
X}
Xsub checkdir {
X # check the directory itself - it was in the searchpath
X local($dir, $reason) = @_;
X # does the directory exist?
X if ( -l $dir ) {
X printf(STDERR "ERROR: I am testing $dir and it is a link.\n");
X } elsif ( -d $dir ) {
X &testdir($dir,$reason);
X } else {
X printf(STDERR "Missing Directory in searchpath : %s\n", $dir);
X }
X}
Xsub testdir {
X # check the directory itself
X local($dir,$reason) = @_;
X local($hit) = 0;
X # does the directory exist?
X ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,
X $size,$atime,$mtime,$ctime,$blksize,$blocks) = stat($dir);
X if ($mode & 002) {
X $hit = 1;
X $WorldWritableDirectoryFound = 1;
X &addworld_directory("$reason AND $dir is WORLD writable", $dir);
X }
X # if group writable AND (not world writable or all)
X if ((!$hit || $all) && ($mode & 020)) {
X $hit = 1;
X $GroupWritableDirectoryFound = 1;
X &addgroup_directory($gid,"$reason AND directory $dir is group writable",
X $dir);
X }
X if (!$hit || $all) {
X &adduser($uid,"$reason AND directory $dir writable by owner"); # owner can write to directory
X }
X}
Xsub checkexecsindir {
X # check each executable in the directory
X local($dir, $problem) = @_;
X local($hit);
X local($program);
X local($myproblem);
X $verbose && printf("check execs in dir $dir, reason: $problem\n");
X opendir(D, $dir) || return 0;
X while ($file = readdir(D)) {
X $myproblem = $problem;
X (($file eq ".") || ($file eq "..")) && next;
X $TotalFiles++; # increase number of files found
X $GroupWritableDirectoryFound && $FilesAfterGroupWritable++;
X $WorldWritableDirectoryFound && $FilesAfterWorldWritable++;
X # this is either a file, a directory, or a symbolic link.
X # if a directory, then don't worry about it.
X $program = "$dir/$file";
X # if file, only worry about it if it's executable,
X
X if ( -l $program) {
X # this is a link. Does it point to a file or to a directory?
X # the file in the searchpath is a symbolic link
X # if it points to a directory, then check who owns the directory
X # it is pointing to
X while ( -l $program ) {
X $link = readlink($program);
X $myproblem .= " AND $program -> $link";
X if ($link !~ /^\// ) {
X # a relative link
X $link = &resolve($program,$link);
X $myproblem .= " ($link) ";
X }
X $debug && printf("Problem is now: %s, new program is %s\n",
X $myproblem, $link);
X $newdir = $link;
X $newdir =~ s,/[^/]+$,,; # remove the executable from the path, and check the directory
X $debug && printf("YES: The directory to check now is %s\n",
X $newdir);
X &ProgramUsesDir($newdir);
X &checkupdir($newdir, "$myproblem ", $NOSEARCHPATH);
X $program = $link;
X }
X # no longer a link, it might be a file of directory
X # get the stat on the final file
X ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,
X $size,$atime,$mtime,$ctime,$blksize,$blocks) = stat($link);
X if (!defined($dev)) {
X # find where it's pointing
X !$brief && printf("Warning: symbolic link %s/%s pointing to missing file: %s\n",
X $dir,$file, $link);
X &checkmissingdir($link,$program);
X } elsif ( -d $link ) {
X # a symbolic link points to a directory.
X # this is only a problem if the directory pointing to is inside
X # a directory that can be modified
X $verbose && printf("\n$dir/$file points to directory $link\n");
X $newdir = $link;
X $newdir =~ s,/[^/]+$,,;
X $verbose && printf("HEY: $link is a directory, and $newdir should be checked\n");
X &checkupdir($newdir, "$dir/$file -> $link AND ",$NOSEARCHPATH);
X } else {
X# printf("$program points to file $link\n");
X $hit = 0;
X
X if ($mode & 0111) { # is this file executable?
X ($hit = ($mode & 002)) && &addworld_file("$dir/$file -> $link AND $link is WORLD writable", "$dir/$file");
X ($hit = ($mode & 020)) && ($all || !$hit) && &addgroup_file($gid,"file $dir/$file -> $link AND $link is group writable", "$dir/$file");
X }
X ($all || !$hit) && &adduser($uid,"file $dir/$file -> $link modifiable by owner"); # owner can modify the target file, and make it executable if it isn't
X # also check by going up the tree of the executable
X $newdir = $link;
X $newdir =~ s,/[^/]+$,,;
X
X $debug && printf("YO: link: $link, newdir: $newdir, calling checkupdir\n");
X &ProgramUsesDir($newdir);
X &checkupdir($newdir, "$dir/$file -> $link AND ",$NOSEARCHPATH); # did I do this twice?
X }
X #
X # if it is a file, check the permission of the file
X #
X } elsif ( -d "$dir/$file" ) { # Not a link, maybe a directory?
X # yes a directory in our search path. Does this mean anything?
X # I guess not. We already go up the directory path
X
X } else { # not a link or directory - a file
X # stat the file
X
X &ProgramUsesDir($dir);
X &testfile("$dir/$file", "$dir/$file executable in path");
X }
X }
X close(D);
X}
X
Xsub testfile {
X local($file,$reason) = @_;
X ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,
X $size,$atime,$mtime,$ctime,$blksize,$blocks) = stat($file);
X $hit = 0;
X if ($mode & 0111) { # is this file executable?
X# printf("Executable $dir/$file seen\n");
X # increase the number of programs seen
X # if the "." directory has been seen, then
X # this program can be trojanized
X $dot && $programsafterdot++;
X
X if ($mode & 002) {
X # world writable
X $hit = 1;
X &addworld_file("$reason AND $file is WORLD writable", "$file");
X }
X # if group writable AND (not world writable or all)
X if ((!$hit || $all) && ($mode & 020)) {
X $hit = 1;
X &addgroup_file($gid,"$reason AND file $file is group writable", "$file");
X }
X }
X # it doesn't matter if the file is executable or not,
X # the owner can make it executable
X ($all || !$hit) && &adduser($uid,"$reason AND file $file modifiable by owner");
X}
X
X
Xsub adduser {
X local($user,$dir) = @_;
X if (defined($user{$user})) {
X if ($report_all) {
X ($user != "0" && $user != $< ) && printf("user %s can do it because of %s\n", $user, $dir);
X } else {
X $debug && $verbose && printf("user %s can do it because of %s\n", $user, $dir);
X }
X
X # add it to the list
X $user{$user} .= "\n$dir";
X $usercount{$user}++;
X
X } else {
X $user{$user} = $dir;
X $usercount{$user} = 1;
X $verbose && printf("user %s can do it because of %s\n", $user, $dir);
X }
X}
Xsub addgroup_directory {
X local($gid,$reason,$dir) = @_;
X# $GroupWritableDirectoryFound = 1;
X if (!defined($group_writable{$dir})) {
X &addgroup($gid, $reason, $dir);
X $group_writable{$dir} = 1;
X } else {
X $group_writable{$dir}++ ;
X $verbose && printf("Directory '$dir' found again\n");