package KUANG;

main::pdebug "Loading Kuang rule now ...", 6.1;

#
writers()
# Get the writers of the named file or directory - return as
(UID, GID, OTHER)
# triplet.  Owner can always write, since he can chmod
the file if he
# wants. 
#
# Calls: main::stat()
# Called From:
KUANG::eval_access().
# Expects: A filename as the only argument.
#
Returns: A string containing the owner, group and other permissions

#	associated with the filename given on invocation.
# Side effects:
none.
# Errors: If the file doesn't exist (as tested with the "-e" test)
the 
#	string returned is empty.
#
# (fixme) are there any problems in this
sort of builtin rule?  should
# we make this knowledge more explicit?
#
sub
writers {
    my($target) = @_;
    my(@srtn,$gid,$other,$uid);
    

@srtn = main::stat($target);
    if ( $#srtn != -1 ) {
        main::pdebug

            "stat(\"$target\"), mode: $srtn[2], uid/gid:
$srtn[4]/$srtn[5]",
            '6.3';
        $uid = $srtn[4];

$gid = $srtn[5];
        if (($srtn[2] & 020) != 020) {
            $gid =
"";
        }
	if ( ( $srtn[2] & 02 ) == 02 ) {
            $other = 1;

} else {
           $other = 0;
    	}
    } else {
	($uid,$gid,$other)
= ("","","");
    }

    return($uid, $gid, $other);
}

# eval_access()
#
Given a filename, add appropriate plans reflecting the access to the file
#
itself and the directory which contains it.
#
# Called from
KUANG::control_file_attacks().
# Calls KUANG:writers()
# Expects: a
filename and a reference to a "new_plans" associative array.
# Returns:
none.
# Side effects: Creates new entries in the "new_plans" assoc.
array.
# Error checking: none.
#
sub eval_access {
	my($ob,$new_plans_r) =
@_;

	# See if we can overwrite the file
        my($owner, $group, $other)
= &writers($ob);
	# owner can w file always with chmod.
	$$new_plans_r{"w
$ob u $owner"} = "$ob is writeable by uid $owner" 
            if ($owner
ne "");
	$$new_plans_r{"w $ob g $group"} = "$ob is writeable by gid $group"

            if ($group ne "");
	$$new_plans_r{"w $ob u .*"} = "$ob is
world writeable" if ($other);

	# We can replace the file if we can write
to 
	# the directory containing the file.
        my($dirname);
        (
$dirname = $ob ) =~ s/(.+)\/[^\/]+/$1/;
        ($owner, $group, $other) =
&writers($dirname);
	$$new_plans_r{"r $ob u $owner"} = 

"directory of $ob is writeable by uid $owner" if ($owner ne
"");
	$$new_plans_r{"r $ob g $group"} = 
            "directory of $ob is
writeable by gid $group" if ($group ne "");
	$$new_plans_r{"r $ob u .*"} =

            "directory of $ob is world writeable" if ($other);
} # end of
eval_access()

# control_file_attacks()
#    This routine establishes some
rules indicating that access to a given 
#    set of files will allow
access to the root account. It then goes 
#    through the list of files to
create rules about who does have access 
#    to these files.
#
# Expects:
A reference to a "new_plans" associative array.
# Calls:
KUANG::eval_access()
# Called by: KUANG::run_KUANG()
# Returns: nothing.
#
Side-effects: Creates new entries in "new_plans" assoc. array.
# Errors:
none.
sub control_file_attacks {
    my($new_plans_r) = pop(@_);

    #

# Controlling files for root and users. If any of these files can
    # be
replaced or written by non-root user, then the system is 
    #
vulnerable.
    my(@sys_files) = ("/etc/passwd","/usr/lib/aliases", 

"/etc/aliases", "/etc/rc", "/etc/rc.boot", "/etc/rc.single", 

"/etc/rc.config", "/etc/rc.local", "/usr/lib/crontab",

"/usr/spool/cron/crontabs","/etc/hosts.eqiv");
    foreach (@sys_files) {

# first we create the rules pertaining to the control-files ...

$$new_plans_r{"u 0 r $_"} = 
            "root access via replaceable
$_";
        $$new_plans_r{"u 0 w $_"} = 
            "root access via.
writeable $_";
        # then we create rules describing the access to
these files.
        eval_access($_,$new_plans_r);
    }

    ## Check uid
specific "home" directory and "control files". If any
    ## are writeable
by other than root or the uidthemselves, then that 
    ## uid can be
accessed.
    my(@pwent);
    while (  @pwent = main::getpwent ) {

my($home_s) = $pwent[7];
        my($uid_s) = $pwent[2];
        if (
$home_s ne "" && main::stat($home_s) ) {

eval_access($home_s,$new_plans_r);
            $home_s = "" if ($home_s eq
"/");
            foreach
(".rhosts",".login",".logout",".cshrc",".profile") {

my($target) = "$home_s/$_";
                if ( main::stat($target) ) {

$$new_plans_r{"u $uid_s r $target"} = 

"Access user if I can replace $_ control file";

$$new_plans_r{"u $uid_s w $target"} = 
                        "Access user
if I can write $_ control file";
                    eval_access("$target",
$new_plans_r);
                }
            }
        }
    }
} # end of
control_file_attacks()

# gid_attacks ()
#
# Called by: anonymous return
for this file.
sub gid_attacks {
	my($new_plans_r) = pop(@_);

	#
	# Plans
for attacking GIDs...
        # N.B. At this stage all this routine does is
load the plans. It
        # should evaluate the state of the files first,
to see if the plan
        # is worth loading.
	#
	# If we can write or
replace /etc/group we can become any group
	#				  

$$new_plans_r{"g .* r /etc/group"} = "/etc/group can be replaced";

$$new_plans_r{"g .* w /etc/group"} = "/etc/group can be overwritten";

eval_access("/etc/group", $new_plans_r);
} # end of gid_attacks()

# main
for KUANG
# the "well defined" name of the KuangPlus routine which will, in
turn, invoke 
# the subroutines created above.
#
# Expects: nothing
#
Calls: KUANG::control_file_attacks()
# Called by: KuangPlus::kuangplus()
#
Returns: a new associative array of plans.
# Side effects: none.
# Errors:
none.

my(@uname) = main::uname();
if ( $uname[0] =~ /(Linux|FreeBSD)/ ) {

main::pdebug "Invoking KUANG rule set\n", 6.3;

KUANG::control_file_attacks(\%main::new_plans);

KUANG::gid_attacks(\%main::new_plans);
} else {
    main::pdebug "Not
appropriate platform for KUANG rules\n", 6.3;
}

