Tryag File Manager
Home
-
Turbo Force
Current Path :
/
usr
/
lib
/
python2.4
/
site-packages
/
Upload File :
New :
File
Dir
//usr/lib/python2.4/site-packages/jail.py
#!/usr/bin/python """ Support for jails on Linux Technical Plan. This module provides classes for Jail objects and for reading the libchroot configuration file Usage: from jail import Jail from jail import JailCfg """ __metaclass__ = type import sys import os import pwd import re import syslog import itertools import subprocess import datetime import time import ldap from stat import * # Setup syslog. syslog.openlog('jail-subsystem') class JailError(Exception): """Jail Specific Errors""" class Jail: """ Describes a jail object. Public Methods: create destroy isactive touch """ def __init__(self, uid): """ Create a Jail object """ uid = int(uid) self.cfg = JailCfg() self.uid = uid self.gid = uid # this is always the same on our platform self.jailpath = self.cfg.jailroot + str(self.uid) self.stales = [] # build our stale list. for stale in os.listdir(self.cfg.removedir): if stale.startswith('%s-stale' % self.uid): self.stales.append(os.path.normpath('%s/%s' % (self.cfg.removedir, stale))) def __str__(self): """Print some useful information about this jail""" tag = "stale" if self.active: tag = "active" else: tag = "stale" # Eat the missing lock file error as this may happen somewhat often. # (SA's may remove, etc...) try: age = self.age except: age = "ERROR" return "%s [age=%s] jail %s @ %s" % \ (tag, age, self.uid, self.jailpath) def __lockfilePath(self): return self.cfg.jaillocks + str(self.uid) def __hasProcesses(self): """ Scan the /proc directory for anthing I own. If I own something and it's running under a jail directory, then a jail has processes. """ for d in os.listdir("/proc"): cpath = "/proc/%s" % d if os.stat(cpath).st_uid == self.uid and not os.readlink("%s/root" % cpath) == "/": return True return False def killProcesses(self): """ Find any process running under this UID. Send them a kill signal and wait for them to die before returning """ for pid in os.listdir("/proc"): try: cpath = "/proc/%s" % pid if os.stat(cpath).st_uid == self.uid and not os.readlink("%s/root" % cpath) == "/": # Send a sigterm os.kill(int(pid), 15) if s.path.isdir(cpath): time.sleep(1) # Sleep for a second and then kill if os.stat(cpath).st_uid == self.uid: os.kill(int(pid), 9) except OSError, err: if err.errno == 2: # We killed it? pass else: raise def __isActive(self): """ Stat the Lock file and determine if the access time has updated on the configured interval. If so, return True. Otherwise return false """ active = True try: if self.age > int(self.cfg.staletime): active = False except OSError, err: if err.errno == 2: active = False else: raise return active def create(self): """ create jail for given user """ os.stat(self.directory) # let exceptions raise here parts = self.directory.split("/") parts[-1] = ".%s-tmp" % parts[-1] userTemp = "/".join(parts) try: os.stat(userTemp) except OSError, err: if err.errno == 2: os.mkdir(userTemp, 0755) os.chown(userTemp, self.uid, self.gid) else: raise try: os.mkdir(self.jailpath, 0755) except OSError, e: if e.errno == 17: raise JailError('jail already exists @ %s' % self.jailpath) else: raise jailDirList = ["/dev", "/dev/pts", "/proc", "/sbin", "/bin", "/usr", "/etc", "/lib", "/sys", "/boot", "/var", "/var/spool/cron"] for k in jailDirList: self.__mount(k, self.jailpath + k) self.__mount(self.directory, self.jailpath + self.directory) self.__mount(userTemp, self.jailpath + "/tmp") self.__mount(userTemp, self.jailpath + "/var/tmp") def queueDestroy(self): """ Move the jail to a temporary directory location so that delete failures do not cause ongoing problems. """ target = os.path.join(self.cfg.removedir, '%s-stale-%f' % (self.uid, time.time())) os.rename(self.jailpath, target) def purge(self): """ Remove all jails from the pending deletion directory. Skip over errored jails. """ # Iterate through the list and try to umount directories jailDirListRev = ["/dev", "/proc", "/sbin", "/bin", "/usr", "/etc", "/lib", "/sys", "/boot", "/var"] for pending in list(self.stales): # Actually mount the directories after the checks have passed. try: self.__umount(pending + "/var/tmp", remove=False) self.__umount(pending + "/tmp") self.__umount(pending + self.directory) # Need a little extra bit of logic here - the home directory # contains an arbitrary number of empty subdirectories. homedirdirs = self.directory.split(os.path.sep) for d in range(len(homedirdirs) - 1, 1, -1): os.rmdir(pending + os.path.sep.join(homedirdirs[0:d])) self.__umount(pending + "/dev/pts", remove=False) self.__umount(pending + "/var/spool/cron", remove=False) for k in jailDirListRev: self.__umount(pending + k) os.rmdir(pending) self.stales.remove(pending) syslog.syslog('%s purged' % pending) except Exception, e: syslog.syslog('error purging %s (tied to %s): %s' % \ (pending, self.uid, e)) def touch(self): pass def __getDirectory(self): ldap_object = ldap.open(self.cfg.ldap_host) ldap_object.simple_bind_s() filter = "(ou=%d)" % self.uid result = ldap_object.search_s(self.cfg.ldap_basedn, ldap.SCOPE_SUBTREE, filter, ['acBasePath']) return result[0][1]['acBasePath'][0] def __getExists(self): return os.path.exists(self.jailpath) def __getAge(self): atime = os.stat(self.cfg.jaillocks + str(self.uid))[ST_ATIME] return int(time.time()) - atime def __mount(self, dir, mnt): """ Mount dir on mnt - making the directory if necessary """ try: os.makedirs(mnt, 0755) except OSError, e: if e.errno == 17: pass else: raise # Run the bind mount. code = subprocess.call(["/bin/mount", "--bind", "-n", dir, mnt]) if code != 0: raise JailError('subprocess mount error: %d' % code) def __umount(self, mnt, remove=True): """ Unmount a mountpoint """ code = subprocess.call(["/bin/umount", "-l", "-n", mnt]) if code != 0: raise JailError('subprocess umount error %d' % code) if (remove): os.rmdir(mnt) # Properties collection... lockfile = property(__lockfilePath) active = property(__isActive) has_processes = property(__hasProcesses) age = property(__getAge) directory = property(__getDirectory) exists = property(__getExists) class JailCfg: def __init__(self, configfile='/etc/libchroot.conf'): """ Reads the config file and populates the object with the results. You can either pass a path to config file or set it in the environment variable LIBCHROOT_CONFIG_FILE. Public Attributes: basedir configfile jailtool jaillocks jailroot maxlockage """ self.configfile = configfile self.staletime = 3600 self.maxlockage = 604800 self.basedir = None self.jailtool = None self.jaillocks = None self.jailroot = None self.removedir = None if "LIBCHROOT_CONFIG_FILE" in os.environ: self.configfile = os.environ['LIBCHROOT_CONFIG_FILE'] for line in (open(self.configfile, 'r')): # Strip leading and trailing whitespace: line = line.strip() # Strip comments if line.find('#') > -1: line, comment = line.split('#', 1) try: key, value = re.split('\s+', line, 1) if key == "root": self.basedir = value self.jailroot = value + "/jails/" self.jaillocks = value + "/locks/" self.removedir = value + '/removal/' elif key == "jailtool": self.jailtool = value elif key == "staletime": self.staletime = int(value) elif key == "ldap_host": self.ldap_host = value elif key == "ldap_basedn": self.ldap_basedn = value elif key == "maxlockage": self.maxlockage = int(value) #XXX -- why? except ValueError: pass # These options are required. if not self.basedir or not self.jailtool: if not value: raise JailError("Configuration error, root and jailtool cannot be null") # Don't create a new object for each function call. function_config = JailCfg() def all_locks(filter_method=None): """ Return a list of all locks. If filter is not none, only return locks for which filter_method returns True. """ cfg = function_config for i in [e for e in os.listdir(cfg.jaillocks) if re.compile(r'^[0-9]+$').match(e)]: locks = (int(i), os.path.join(cfg.jaillocks, i)) if filter_method: if filter_method(locks): yield locks else: yield locks def all_jails(pending_purge=False, filter_method=None): """ Generator that yields jail UIDs. Setting pending_purge=True will only return jail instances where we have pending deletions. Filter method... yield Jail j if filter_method(j) == True. """ cfg = function_config target_dir = cfg.jailroot unique = set() # Quicker than O(n) list lookup. # If we want the pending removed directories, # use cfg.removedir instead. if pending_purge: target_dir = cfg.removedir # skip current dir. for dir in os.listdir(target_dir): if dir.startswith('.'): continue # user-date-purge file names. if pending_purge: dir = dir.split('-')[0] # Ensure we don't include jails for queued to purge # more than once. if dir in unique: continue unique.add(dir) try: j = Jail(int(dir)) if filter_method: if filter_method(j): yield j else: yield j except Exception, e: syslog.syslog('cannot create jail instance in generator: %s: %s' % (dir, e))