#!/usr/bin/python -E
import os, sys, getopt, socket, random, fcntl
import selinux

PROGNAME = "policycoreutils"

import gettext
gettext.bindtextdomain(PROGNAME, "/usr/share/locale")
gettext.textdomain(PROGNAME)

try:
       gettext.install(PROGNAME,
                       localedir = "/usr/share/locale",
                       unicode=False,
                       codeset = 'utf-8')
except IOError:
       import __builtin__
       __builtin__.__dict__['_'] = unicode


random.seed(None)

def error_exit(msg):
    sys.stderr.write("%s: " % sys.argv[0])
    sys.stderr.write("%s\n" % msg)
    sys.stderr.flush()
    sys.exit(1)

def mount(context):
    if os.getuid() != 0:
        usage(_("Mount options require root privileges"))
    destdir = "/mnt/%s" % context
    os.mkdir(destdir)
    rc = os.system('/bin/mount -t tmpfs tmpfs %s' % (destdir))
    selinux.setfilecon(destdir, context)
    if rc != 0:
        sys.exit(rc)
    os.chdir(destdir)

def umount(dest):
    os.chdir("/")
    destdir = "/mnt/%s" % dest
    os.system('/bin/umount %s' % (destdir))
    os.rmdir(destdir)


def reserve(mcs):
    sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
    sock.bind("\0%s" % mcs)
    fcntl.fcntl(sock.fileno(), fcntl.F_SETFD, fcntl.FD_CLOEXEC)

def gen_context(setype):
    while True:
        i1 = random.randrange(0, 1024)
        i2 = random.randrange(0, 1024)
        if i1 == i2:
            continue
        if i1 > i2:
            tmp = i1
            i1 = i2
            i2 = tmp
        mcs = "s0:c%d,c%d" % (i1, i2)
        reserve(mcs)
        try:
            reserve(mcs)
        except:
            continue
        break
    con = selinux.getcon()[1].split(":")

    execcon = "%s:%s:%s:%s" % (con[0], con[1], setype, mcs)
    
    filecon = "%s:%s:%s:%s" % (con[0], 
                               "object_r", 
                               "%s_file_t" % setype[:-2], 
                               mcs)
    return execcon, filecon


if __name__ == '__main__':
    if selinux.is_selinux_enabled() != 1:
        error_exit("Requires an SELinux enabled system")
        
    def usage(message = ""):
        text = _("""
sandbox [ -m ] [ -t type ] command
""")
        error_exit("%s\n%s" % (message, text))

    setype = "sandbox_t"
    mount_ind = False
    try:
           gopts, cmds = getopt.getopt(sys.argv[1:], "ht:m", 
                                       ["help",
                                        "type=", 
                                        "mount"])
           for o, a in gopts:
                  if o == "-t" or o == "--type":
                         setype = a
                         
                  if o == "-m" or o == "--mount":
                         mount_ind = True

                  if o == "-h" or o == "--help":
                         usage(_("Usage"));
            
           if len(cmds) == 0:
                  usage(_("Command required"))

           execcon, filecon = gen_context(setype)
           rc = -1
           if mount_ind:
                  mount(filecon)

           if cmds[0][0] != "/" and cmds[0][:2] != "./" and cmds[0][:3] != "../":
                  for i in  os.environ["PATH"].split(':'):
                         f = "%s/%s" % (i, cmds[0])
                         if os.access(f, os.X_OK):
                                cmds[0] = f
                                break

           selinux.setexeccon(execcon)
           rc = os.spawnvp(os.P_WAIT, cmds[0], cmds)
           selinux.setexeccon(None)
           
           if mount_ind:
                  umount(filecon)
    except getopt.GetoptError, error:
        usage(_("Options Error %s ") % error.msg)
    except ValueError, error:
        error_exit(error.args[0])
    except KeyError, error:
        error_exit(_("Invalid value %s") % error.args[0])
    except IOError, error:
        error_exit(error.args[1])
    except OSError, error:
        error_exit(error.args[1])
        
    sys.exit(rc)
