Files
xen/tools/security/labelfuncs.sh
T

676 lines
20 KiB
Bash

# *
# * labelfuncs.sh
# *
# * Copyright (C) 2005 IBM Corporation
# *
# * Authors:
# * Stefan Berger <stefanb@us.ibm.com>
# *
# * This program is free software; you can redistribute it and/or
# * modify it under the terms of the GNU General Public License as
# * published by the Free Software Foundation, version 2 of the
# * License.
# *
# *
# * A collection of functions to handle polcies, mapfiles,
# * and ssidrefs.
#
# Find the mapfile given a policy nmame
# Parameters:
# 1st : the name of the policy whose map file is to be found, i.e.,
# chwall
# Results:
# The variable mapfile will hold the realtive path to the mapfile
# for the given policy.
# In case the mapfile could be found, the functions returns a '1',
# a '0' otherwise.
findMapFile ()
{
mapfile="./$1.map"
if [ -r "$mapfile" ]; then
return 1
fi
mapfile="./policies/$1/$1.map"
if [ -r "$mapfile" ]; then
return 1
fi
return 0
}
# Determine the name of the primary policy
# Parameters
# 1st : the path to the mapfile; the path may be relative
# to the current directory
# Results
# The variable primary will hold the name of the primary policy
getPrimaryPolicy ()
{
mapfile=$1
primary=`cat $mapfile | \
awk ' \
{ \
if ( $1 == "PRIMARY" ) { \
res=$2; \
} \
} END { \
print res; \
} '`
}
# Determine the name of the secondary policy
# Parameters
# 1st : the path to the mapfile; the path may be relative
# to the current directory
# Results
# The variable secondary will hold the name of the secondary policy
getSecondaryPolicy ()
{
mapfile=$1
secondary=`cat $mapfile | \
awk ' \
{ \
if ( $1 == "SECONDARY" ) { \
res=$2; \
} \
} END { \
print res; \
} '`
}
#Return where the grub.conf file is.
#I only know of one place it can be.
findGrubConf()
{
grubconf="/boot/grub/grub.conf"
if [ -w $grubconf ]; then
return 1
fi
if [ -r $grubconf ]; then
return 2
fi
return 0
}
# This function sets the global variable 'linux'
# to the name and version of the Linux kernel that was compiled
# for domain 0.
# If this variable could not be found, the variable 'linux'
# will hold a pattern
# Parameters:
# 1st: the path to reach the root directory of the XEN build tree
# where linux-*-xen0 is located at
# Results:
# The variable linux holds then name and version of the compiled
# kernel, i.e., 'vmlinuz-2.6.12-xen0'
getLinuxVersion ()
{
path=$1
linux=""
for f in $path/linux-*-xen0 ; do
versionfile=$f/include/linux/version.h
if [ -r $versionfile ]; then
lnx=`cat $versionfile | \
grep UTS_RELEASE | \
awk '{ \
len=length($3); \
print substr($3,2,len-2) }'`
fi
if [ "$lnx" != "" ]; then
linux="[./0-9a-zA-z]*$lnx"
return;
fi
done
#Last resort.
linux="vmlinuz-2.[45678].[0-9]*[.0-9]*-xen0$"
}
# Find out with which policy the hypervisor was booted with.
# Parameters
# 1st : The complete path to grub.conf, i.e., /boot/grub/grub.conf
#
findPolicyInGrub ()
{
grubconf=$1
linux=`uname -r`
policy=`cat $grubconf | \
awk -vlinux=$linux '{ \
if ( $1 == "title" ) { \
kernelfound = 0; \
policymaycome = 0; \
} \
else if ( $1 == "kernel" ) { \
if ( match($2,"xen.gz$") ) { \
pathlen=RSTART; \
kernelfound = 1; \
} \
} \
else if ( $1 == "module" && \
kernelfound == 1 && \
match($2,linux) ) { \
policymaycome = 1; \
} \
else if ( $1 == "module" && \
kernelfound == 1 && \
policymaycome == 1 && \
match($2,"[0-9a-zA-Z_]*.bin$") ) { \
policymaycome = 0; \
kernelfound = 0; \
polname = substr($2,pathlen); \
len=length(polname); \
polname = substr(polname,0,len-4); \
} \
} END { \
print polname \
}'`
}
# Get the SSID of a domain
# Parameters:
# 1st : domain ID, i.e. '1'
# Results
# If the ssid could be found, the variable 'ssid' will hold
# the currently used ssid in the hex format, i.e., '0x00010001'.
# The funtion returns '1' on success, '0' on failure
getSSIDUsingSecpolTool ()
{
domid=$1
export PATH=$PATH:.
ssid=`secpol_tool getssid -d $domid -f | \
grep -E "SSID:" | \
awk '{ print $4 }'`
if [ "$ssid" != "" ]; then
return 1
fi
return 0
}
# Break the ssid identifier into its high and low values,
# which are equal to the secondary and primary policy references.
# Parameters:
# 1st: ssid to break into high and low value, i.e., '0x00010002'
# Results:
# The variable ssidlo_int and ssidhi_int will hold the low and
# high ssid values as integers.
getSSIDLOHI ()
{
ssid=$1
ssidlo_int=`echo $ssid | awk \
'{ \
len=length($0); \
beg=substr($0,1,2); \
if ( beg == "0x" ) { \
dig = len - 2; \
if (dig <= 0) { \
exit; \
} \
if (dig > 4) { \
dig=4; \
} \
lo=sprintf("0x%s",substr($0,len-dig+1,dig)); \
print strtonum(lo);\
} else { \
lo=strtonum($0); \
if (lo < 65536) { \
print lo; \
} else { \
hi=lo; \
hi2= (hi / 65536);\
hi2_str=sprintf("%d",hi2); \
hi2=strtonum(hi2_str);\
lo=hi-(hi2*65536); \
printf("%d",lo); \
} \
} \
}'`
ssidhi_int=`echo $ssid | awk \
'{ \
len=length($0); \
beg=substr($0,1,2); \
if ( beg == "0x" ) { \
dig = len - 2; \
if (dig <= 0 || \
dig > 8) { \
exit; \
} \
if (dig < 4) { \
print 0; \
exit; \
} \
dig -= 4; \
hi=sprintf("0x%s",substr($0,len-4-dig+1,dig)); \
print strtonum(hi);\
} else { \
hi=strtonum($0); \
if (hi >= 65536) { \
hi = hi / 65536; \
printf ("%d",hi);\
} else { \
printf ("0"); \
} \
} \
}'`
if [ "$ssidhi_int" == "" -o \
"$ssidlo_int" == "" ]; then
return 0;
fi
return 1
}
#Update the grub configuration file.
#Search for existing entries and replace the current
#policy entry with the policy passed to this script
#
#Arguments passed to this function
# 1st : the grub configuration file with full path
# 2nd : the binary policy file name, i.e. chwall.bin
# 3rd : the name or pattern of the linux kernel name to match
# (this determines where the module entry will be made)
#
# The algorithm here is based on pattern matching
# and is working correctly if
# - under a title a line beginning with 'kernel' is found
# whose following item ends with "xen.gz"
# Example: kernel /xen.gz dom0_mem=....
# - a module line matching the 3rd parameter is found
#
updateGrub ()
{
grubconf=$1
policyfile=$2
linux=$3
tmpfile="/tmp/new_grub.conf"
cat $grubconf | \
awk -vpolicy=$policyfile \
-vlinux=$linux '{ \
if ( $1 == "title" ) { \
kernelfound = 0; \
if ( policymaycome == 1 ){ \
printf ("\tmodule %s%s\n", path, policy); \
} \
policymaycome = 0; \
} \
else if ( $1 == "kernel" ) { \
if ( match($2,"xen.gz$") ) { \
path=substr($2,1,RSTART-1); \
kernelfound = 1; \
} \
} \
else if ( $1 == "module" && \
kernelfound == 1 && \
match($2,linux) ) { \
policymaycome = 1; \
} \
else if ( $1 == "module" && \
kernelfound == 1 && \
policymaycome == 1 && \
match($2,"[0-9a-zA-Z]*.bin$") ) { \
printf ("\tmodule %s%s\n", path, policy); \
policymaycome = 0; \
kernelfound = 0; \
dontprint = 1; \
} \
else if ( $1 == "" && \
kernelfound == 1 && \
policymaycome == 1) { \
dontprint = 1; \
} \
if (dontprint == 0) { \
printf ("%s\n", $0); \
} \
dontprint = 0; \
} END { \
if ( policymaycome == 1 ) { \
printf ("\tmodule %s%s\n", path, policy); \
} \
}' > $tmpfile
if [ ! -r $tmpfile ]; then
echo "Could not create temporary file! Aborting."
exit -1
fi
mv -f $tmpfile $grubconf
}
# Display all the labels in a given mapfile
# Parameters
# 1st: Full or relative path to the policy's mapfile
showLabels ()
{
mapfile=$1
if [ ! -r "$mapfile" -o "$mapfile" == "" ]; then
echo "Cannot read from vm configuration file $vmfile."
return -1
fi
getPrimaryPolicy $mapfile
getSecondaryPolicy $mapfile
echo "The following labels are available:"
let line=1
while [ 1 ]; do
ITEM=`cat $mapfile | \
awk -vline=$line \
-vprimary=$primary \
'{ \
if ($1 == "LABEL->SSID" && \
$2 == "VM" && \
$3 == primary ) { \
ctr++; \
if (ctr == line) { \
print $4; \
} \
} \
} END { \
}'`
if [ "$ITEM" == "" ]; then
break
fi
if [ "$secondary" != "NULL" ]; then
LABEL=`cat $mapfile | \
awk -vitem=$ITEM \
'{
if ($1 == "LABEL->SSID" && \
$2 == "VM" && \
$3 == "CHWALL" && \
$4 == item ) { \
result = item; \
} \
} END { \
print result \
}'`
else
LABEL=$ITEM
fi
if [ "$LABEL" != "" ]; then
echo "$LABEL"
found=1
fi
let line=line+1
done
if [ "$found" != "1" ]; then
echo "No labels found."
fi
}
# Get the default SSID given a mapfile and the policy name
# Parameters
# 1st: Full or relative path to the policy's mapfile
# 2nd: the name of the policy
getDefaultSsid ()
{
mapfile=$1
pol=$2
RES=`cat $mapfile \
awk -vpol=$pol \
{ \
if ($1 == "LABEL->SSID" && \
$2 == "ANY" && \
$3 == pol && \
$4 == "DEFAULT" ) {\
res=$5; \
} \
} END { \
printf "%04x", strtonum(res) \
}'`
echo "default NULL mapping is $RES"
defaultssid=$RES
}
#Relabel a VM configuration file
# Parameters
# 1st: Full or relative path to the VM configuration file
# 2nd: The label to translate into an ssidref
# 3rd: Full or relative path to the policy's map file
# 4th: The mode this function is supposed to operate in:
# 'relabel' : Relabels the file without querying the user
# other : Prompts the user whether to proceed
relabel ()
{
vmfile=$1
label=$2
mapfile=$3
mode=$4
if [ ! -r "$vmfile" ]; then
echo "Cannot read from vm configuration file $vmfile."
return -1
fi
if [ ! -w "$vmfile" ]; then
echo "Cannot write to vm configuration file $vmfile."
return -1
fi
if [ ! -r "$mapfile" ] ; then
echo "Cannot read mapping file $mapfile."
return -1
fi
# Determine which policy is primary, which sec.
getPrimaryPolicy $mapfile
getSecondaryPolicy $mapfile
# Calculate the primary policy's SSIDREF
if [ "$primary" == "NULL" ]; then
SSIDLO="0001"
else
SSIDLO=`cat $mapfile | \
awk -vlabel=$label \
-vprimary=$primary \
'{ \
if ( $1 == "LABEL->SSID" && \
$2 == "VM" && \
$3 == primary && \
$4 == label ) { \
result=$5 \
} \
} END { \
if (result != "" ) \
{printf "%04x", strtonum(result)}\
}'`
fi
# Calculate the secondary policy's SSIDREF
if [ "$secondary" == "NULL" ]; then
if [ "$primary" == "NULL" ]; then
SSIDHI="0001"
else
SSIDHI="0000"
fi
else
SSIDHI=`cat $mapfile | \
awk -vlabel=$label \
-vsecondary=$secondary \
'{ \
if ( $1 == "LABEL->SSID" && \
$2 == "VM" && \
$3 == secondary && \
$4 == label ) { \
result=$5 \
} \
} END { \
if (result != "" ) \
{printf "%04x", strtonum(result)}\
}'`
fi
if [ "$SSIDLO" == "" -o \
"$SSIDHI" == "" ]; then
echo "Could not map the given label '$label'."
return -1
fi
ACM_POLICY=`cat $mapfile | \
awk ' { if ( $1 == "POLICY" ) { \
result=$2 \
} \
} \
END { \
if (result != "") { \
printf result \
} \
}'`
if [ "$ACM_POLICY" == "" ]; then
echo "Could not find 'POLICY' entry in map file."
return -1
fi
SSIDREF="0x$SSIDHI$SSIDLO"
if [ "$mode" != "relabel" ]; then
RES=`cat $vmfile | \
awk '{ \
if ( substr($1,0,7) == "ssidref" ) {\
print $0; \
} \
}'`
if [ "$RES" != "" ]; then
echo "Do you want to overwrite the existing mapping ($RES)? (y/N)"
read user
if [ "$user" != "y" -a "$user" != "Y" ]; then
echo "Aborted."
return 0
fi
fi
fi
#Write the output
vmtmp1="/tmp/__setlabel.tmp1"
vmtmp2="/tmp/__setlabel.tmp2"
touch $vmtmp1
touch $vmtmp2
if [ ! -w "$vmtmp1" -o ! -w "$vmtmp2" ]; then
echo "Cannot create temporary files. Aborting."
return -1
fi
RES=`sed -e '/^#ACM_POLICY/d' $vmfile > $vmtmp1`
RES=`sed -e '/^#ACM_LABEL/d' $vmtmp1 > $vmtmp2`
RES=`sed -e '/^ssidref/d' $vmtmp2 > $vmtmp1`
echo "#ACM_POLICY=$ACM_POLICY" >> $vmtmp1
echo "#ACM_LABEL=$label" >> $vmtmp1
echo "ssidref = $SSIDREF" >> $vmtmp1
mv -f $vmtmp1 $vmfile
rm -rf $vmtmp1 $vmtmp2
echo "Mapped label '$label' to ssidref '$SSIDREF'."
}
# Translate an ssidref into its label. This does the reverse lookup
# to the relabel function above.
# This function displays the results.
# Parameters:
# 1st: The ssidref to translate; must be in the form '0x00010002'
# 2nd: Full or relative path to the policy's mapfile
translateSSIDREF ()
{
ssidref=$1
mapfile=$2
if [ ! -r "$mapfile" -o "$mapfile" == "" ]; then
echo "Cannot read from vm configuration file $vmfile."
return -1
fi
getPrimaryPolicy $mapfile
getSecondaryPolicy $mapfile
if [ "$primary" == "NULL" -a "$secondary" == "NULL" ]; then
echo "There are no labels for the NULL policy."
return
fi
getSSIDLOHI $ssidref
ret=$?
if [ $ret -ne 1 ]; then
echo "Error while parsing the ssid ref number '$ssidref'."
fi;
let line1=0
let line2=0
while [ 1 ]; do
ITEM1=`cat $mapfile | \
awk -vprimary=$primary \
-vssidlo=$ssidlo_int \
-vline=$line1 \
'{ \
if ( $1 == "LABEL->SSID" && \
$3 == primary && \
int($5) == ssidlo ) { \
if (l == line) { \
print $4; \
exit; \
} \
l++; \
} \
}'`
ITEM2=`cat $mapfile | \
awk -vsecondary=$secondary \
-vssidhi=$ssidhi_int \
-vline=$line2 \
'{ \
if ( $1 == "LABEL->SSID" && \
$3 == secondary && \
int($5) == ssidhi ) { \
if (l == line) { \
print $4; \
exit; \
} \
l++; \
} \
}'`
if [ "$secondary" != "NULL" ]; then
if [ "$ITEM1" == "" ]; then
let line1=0
let line2=line2+1
else
let line1=line1+1
fi
if [ "$ITEM1" == "" -a \
"$ITEM2" == "" ]; then
echo "Could not determine the referenced label."
break
fi
if [ "$ITEM1" == "$ITEM2" ]; then
echo "Label: $ITEM1"
break
fi
else
if [ "$ITEM1" != "" ]; then
echo "Label: $ITEM1"
else
if [ "$found" == "0" ]; then
found=1
else
break
fi
fi
let line1=line1+1
fi
done
}