diff options
Diffstat (limited to 'share')
-rw-r--r-- | share/.svnignore | 6 | ||||
-rw-r--r-- | share/CHANGES | 73 | ||||
-rw-r--r-- | share/Config.py | 44 | ||||
-rw-r--r-- | share/ConfigFile.py | 453 | ||||
-rw-r--r-- | share/Log.py | 54 | ||||
-rw-r--r-- | share/Makefile | 45 | ||||
-rwxr-xr-x | share/Perms.py | 305 | ||||
-rw-r--r-- | share/README | 87 | ||||
-rwxr-xr-x | share/compile.py | 17 | ||||
-rwxr-xr-x | share/draksec_help.py | 65 | ||||
-rw-r--r-- | share/libmsec.py | 1391 | ||||
-rwxr-xr-x | share/man.py | 67 | ||||
-rwxr-xr-x | share/msec | 85 | ||||
-rwxr-xr-x | share/msec.py | 290 | ||||
-rwxr-xr-x | share/shadow.py | 116 |
15 files changed, 0 insertions, 3098 deletions
diff --git a/share/.svnignore b/share/.svnignore deleted file mode 100644 index 17005aa..0000000 --- a/share/.svnignore +++ /dev/null @@ -1,6 +0,0 @@ -*.pyo -*.pyc -*.flog -mseclib.man -mseclib.py -level.* diff --git a/share/CHANGES b/share/CHANGES deleted file mode 100644 index 22e546a..0000000 --- a/share/CHANGES +++ /dev/null @@ -1,73 +0,0 @@ -changes in version 0.30 -======================= - - * don't lower security if the admin has already augmented it (when called without argument). - * splitted functions that worked on multiple levels. - -changes between version 0.18 and 0.19 -===================================== - -msec utility changes: - - * no password in level 0 - -Periodic security checks changes: - - * config file is now in /var/lib/msec/security.conf and can -be overriden by /etc/security/msec/security.conf. - -changes between version 0.17 and 0.18 -===================================== - -msec utility changes: - - * allow /etc/security/msec/level.local to override the default -setting of the level. - * promisc_check.sh works now. - * added mseclib man page. - -changes between version 0.16 and 0.17 -===================================== - -msec utility changes: - - * handle shell timeout (level 4 and 5) - * limit shell history (level 4 and 5) - * su only for wheel group (level 5) - * sulogin for single user mode (level 4 and 5) - * various sysctl.conf settings for icmp and network parameters - * password aging (level 4 and 5) - * suppress /etc/issue.net (level 4 and 5) and /etc/issue (level 5) - * removed manipulation of the groups of users - * removed removal of services - * logging in syslog according to the guideline for explanations in tools - * more correct prevention of direct root logins - * rewritten in python - -msec can be used to change level and it's also run hourly by cron to -maintain the security level on the system. Only the minimum of changes -on the filesystem are applied and the minimum of programs started. - -Periodic security checks changes: - - * added rpm database checks (rpm -va and rpm -qa) - * report when a user other than root is at uid 0 - * diff_check reports even when the log is empty - * use chkrootkit if present. - -Permissions settings changes: - - * / - * removed audio group handling because it has always conflicted with pam_console - * handle /var/log sub-directories in a generic manner - * /etc/rc.d/init.d/* - * corrected ssh and ping related paths - * /etc/sysconfig - * /proc - * corrected gcc files - * rpm related files to avoid exposing what is installed - * /var/lock/subsys - * added a local.perm to allow modifications without modifying level perms - * corrected all the inconsistencies between levels to be able to change and come back -without problem - * rewritten in python diff --git a/share/Config.py b/share/Config.py deleted file mode 100644 index 14699b4..0000000 --- a/share/Config.py +++ /dev/null @@ -1,44 +0,0 @@ -#--------------------------------------------------------------- -# Project : Mandriva Linux -# Module : msec -# File : Config.py -# Version : $Id$ -# Author : Frederic Lepied -# Created On : Thu Dec 6 19:54:35 2001 -# Purpose : configuration settings -#--------------------------------------------------------------- - -CONFIG='/etc/security/msec2.conf' - -_config={ 'root' : '', - 'run_commands': 1, - 'log': 'syslog', - } -try: - execfile(CONFIG, _config) -except IOError: - #sys.stderr.write("no config file in %s. Using default values.\n" % CONFIG) - pass - -def get_config(name, default=None): - try: - return _config[name] - except KeyError: - return default - -def set_config(name, value): - _config[name] = value - -# def converthexa(array): -# result="" -# for c in array: -# o=ord(c) -# d=int(o/16) -# u=o-(d*16) -# result=result + "%x%x" % (d, u) -# return result -# -# def hashstring(str): -# return converthexa(md5.new(str).digest()) - -# Config.py ends here diff --git a/share/ConfigFile.py b/share/ConfigFile.py deleted file mode 100644 index 26a93e6..0000000 --- a/share/ConfigFile.py +++ /dev/null @@ -1,453 +0,0 @@ -#--------------------------------------------------------------- -# Project : Mandriva Linux -# Module : msec -# File : ConfigFile.py -# Version : $Id$ -# Author : Frederic Lepied -# Created On : Wed Dec 5 21:42:49 2001 -# Purpose : class abstraction to handle configuration -# files. -#--------------------------------------------------------------- - -import re -import string -import os -import stat -import Config -import commands -from Log import * -import gettext - -STRING_TYPE = type('') - -try: - cat = gettext.Catalog('msec') - _ = cat.gettext -except IOError: - _ = str - -BEFORE=0 -INSIDE=1 -AFTER=2 - -space = re.compile('\s') - -class ConfigFiles: - def __init__(self): - self.files = {} - self.modified_files = [] - self.action_assoc = [] - - def add(self, file, path): - self.files[path] = file - - def modified(self, path): - if not path in self.modified_files: - self.modified_files.append(path) - - def get_config_file(self, path, suffix): - try: - return self.files[path] - except KeyError: - return ConfigFile(path, suffix, self) - - def add_config_assoc(self, regex, action): - self.action_assoc.append((re.compile(regex), action)) - -all_files=ConfigFiles() - -def move(old, new): - try: - os.unlink(new) - except OSError: - pass - try: - os.rename(old, new) - except: - error('rename %s %s: %s' % (old, new, str(sys.exc_value))) - -class ConfigFile: - def __init__(self, path, suffix=None, meta=all_files): - self.meta=meta - self.path = Config.get_config('root', '') + path - self.is_modified = 0 - self.is_touched = 0 - self.is_deleted = 0 - self.is_moved = 0 - self.suffix = suffix - self.lines = None - self.sym_link = None - self.meta.add(self, path) - - def get_lines(self): - if self.lines == None: - file=None - try: - file = open(self.path, 'r') - except IOError: - if self.suffix: - try: - moved = self.path + self.suffix - file = open(moved, 'r') - move(moved, self.path) - self.meta.modified(self.path) - except IOError: - self.lines = [] - else: - self.lines = [] - if file: - self.lines = string.split(file.read(), "\n") - file.close() - return self.lines - - def append(self, value): - lines = self.lines - l = len(lines) - if l > 0 and lines[l - 1] == '': - lines.insert(l - 1, value) - else: - lines.append(value) - lines.append('') - - def modified(self): - self.is_modified = 1 - return self - - def touch(self): - self.is_touched = 1 - return self - - def symlink(self, link): - self.sym_link = link - return self - - def exists(self, really=0): - return os.path.exists(self.path) or (not really and self.suffix and os.path.exists(self.path + self.suffix)) - - def move(self, suffix): - self.suffix = suffix - self.is_moved = 1 - - def unlink(self): - self.is_deleted = 1 - self.lines=[] - return self - - def write(self): - if self.is_deleted: - if self.exists(): - try: - os.unlink(self.path) - except: - error('unlink %s: %s' % (self.path, str(sys.exc_value))) - log(_('deleted %s') % (self.path,)) - elif self.is_modified: - content = string.join(self.lines, "\n") - mkdir_p(os.path.dirname(self.path)) - file = open(self.path, 'w') - file.write(content) - file.close() - self.meta.modified(self.path) - elif self.is_touched: - if os.path.exists(self.path): - try: - os.utime(self.path, None) - except: - error('utime %s: %s' % (self.path, str(sys.exc_value))) - elif self.suffix and os.path.exists(self.path + self.suffix): - move(self.path + self.suffix, self.path) - try: - os.utime(self.path, None) - except: - error('utime %s: %s' % (self.path, str(sys.exc_value))) - else: - self.lines = [] - self.is_modified = 1 - file = open(self.path, 'w') - file.close() - log(_('touched file %s') % (self.path,)) - elif self.sym_link: - done = 0 - if self.exists(): - full = os.lstat(self.path) - if stat.S_ISLNK(full[stat.ST_MODE]): - link = os.readlink(self.path) - # to be fixed: resolv relative symlink - done = (link == self.sym_link) - if not done: - try: - os.unlink(self.path) - except: - error('unlink %s: %s' % (self.path, str(sys.exc_value))) - log(_('deleted %s') % (self.path,)) - if not done: - try: - os.symlink(self.sym_link, self.path) - except: - error('symlink %s %s: %s' % (self.sym_link, self.path, str(sys.exc_value))) - log(_('made symbolic link from %s to %s') % (self.sym_link, self.path)) - - if self.is_moved: - move(self.path, self.path + self.suffix) - log(_('moved file %s to %s') % (self.path, self.path + self.suffix)) - self.meta.modified(self.path) - self.is_touched = 0 - self.is_modified = 0 - self.is_deleted = 0 - self.is_moved = 0 - - def set_shell_variable(self, var, value, start=None, end=None): - regex = re.compile('^' + var + '="?([^#"]+)"?(.*)') - lines = self.get_lines() - idx=0 - value=str(value) - start_regexp = start - - if start: - status = BEFORE - start = re.compile(start) - else: - status = INSIDE - - if end: - end = re.compile(end) - - idx = None - for idx in range(0, len(lines)): - line = lines[idx] - if status == BEFORE: - if start.search(line): - status = INSIDE - else: - continue - elif end and end.search(line): - break - res = regex.search(line) - if res: - if res.group(1) != value: - if space.search(value): - lines[idx] = var + '="' + value + '"' + res.group(2) - else: - lines[idx] = var + '=' + value + res.group(2) - self.modified() - log(_('set variable %s to %s in %s') % (var, value, self.path,)) - return self - if status == BEFORE: - # never found the start delimiter - log(_('WARNING: never found regexp %s in %s, not writing changes') % (start_regexp, self.path)) - return self - if space.search(value): - s = var + '="' + value + '"' - else: - s = var + '=' + value - if idx == None or idx == len(lines): - self.append(s) - else: - lines.insert(idx, s) - - self.modified() - log(_('set variable %s to %s in %s') % (var, value, self.path,)) - return self - - def get_shell_variable(self, var, start=None, end=None): - if end: - end=re.compile(end) - if start: - start=re.compile(start) - regex = re.compile('^' + var + '="?([^#"]+)"?(.*)') - lines = self.get_lines() - llen = len(lines) - start_idx = 0 - end_idx = llen - if start: - found = 0 - for idx in range(0, llen): - if start.search(lines[idx]): - start_idx = idx - found = 1 - break - if found: - for idx in range(start_idx, llen): - if end.search(lines[idx]): - end_idx = idx - break - else: - start_idx = 0 - for idx in range(end_idx - 1, start_idx - 1, -1): - res = regex.search(lines[idx]) - if res: - return res.group(1) - return None - - def get_match(self, regex, replace=None): - r=re.compile(regex) - lines = self.get_lines() - for idx in range(0, len(lines)): - res = r.search(lines[idx]) - if res: - if replace: - s = substitute_re_result(res, replace) - return s - else: - return lines[idx] - return None - - def replace_line_matching(self, regex, value, at_end_if_not_found=0, all=0, start=None, end=None): - # if at_end_if_not_found is a string its value will be used as the string to inster - r=re.compile(regex) - lines = self.get_lines() - matches = 0 - - if start: - status = BEFORE - start = re.compile(start) - else: - status = INSIDE - - if end: - end = re.compile(end) - - idx = None - for idx in range(0, len(lines)): - line = lines[idx] - if status == BEFORE: - if start.search(line): - status = INSIDE - else: - continue - elif end and end.search(line): - break - res = r.search(line) - if res: - s = substitute_re_result(res, value) - matches = matches + 1 - if s != line: - log(_("replaced in %s the line %d:\n%s\nwith the line:\n%s") % (self.path, idx, line, s)) - lines[idx] = s - self.modified() - if not all: - return matches - if matches == 0 and at_end_if_not_found: - if type(at_end_if_not_found) == STRING_TYPE: - value = at_end_if_not_found - log(_("appended in %s the line:\n%s") % (self.path, value)) - if idx == None or idx == len(lines): - self.append(value) - else: - lines.insert(idx, value) - self.modified() - matches = matches + 1 - return matches - - def insert_after(self, regex, value, at_end_if_not_found=0, all=0): - matches = 0 - r=re.compile(regex) - lines = self.get_lines() - for idx in range(0, len(lines)): - res = r.search(lines[idx]) - if res: - s = substitute_re_result(res, value) - log(_("inserted in %s after the line %d:\n%s\nthe line:\n%s") % (self.path, idx, lines[idx], s)) - lines.insert(idx+1, s) - self.modified() - matches = matches + 1 - if not all: - return matches - if matches == 0 and at_end_if_not_found: - log(_("appended in %s the line:\n%s") % (self.path, value)) - self.append(value) - self.modified() - matches = matches + 1 - return matches - - def insert_before(self, regex, value, at_top_if_not_found=0, all=0): - matches = 0 - r=re.compile(regex) - lines = self.get_lines() - for idx in range(0, len(lines)): - res = r.search(lines[idx]) - if res: - s = substitute_re_result(res, value) - log(_("inserted in %s before the line %d:\n%s\nthe line:\n%s") % (self.path, idx, lines[idx], s)) - lines.insert(idx, s) - self.modified() - matches = matches + 1 - if not all: - return matches - if matches == 0 and at_top_if_not_found: - log(_("inserted at the top of %s the line:\n%s") % (self.path, value)) - lines.insert(0, value) - self.modified() - matches = matches + 1 - return matches - - def insert_at(self, idx, value): - lines = self.get_lines() - try: - lines.insert(idx, value) - log(_("inserted in %s at the line %d:\n%s") % (self.path, idx, value)) - self.modified() - return 1 - except KeyError: - return 0 - - def remove_line_matching(self, regex, all=0): - matches = 0 - r=re.compile(regex) - lines = self.get_lines() - for idx in range(len(lines) - 1, -1, -1): - res = r.search(lines[idx]) - if res: - log(_("removing in %s the line %d:\n%s") % (self.path, idx, lines[idx])) - lines.pop(idx) - self.modified() - matches = matches + 1 - if not all: - return matches - return matches - -# utility funtions - -def substitute_re_result(res, s): - for idx in range(0, (res.lastindex or 0) + 1): - subst = res.group(idx) or '' - s = string.replace(s, '@' + str(idx), subst) - return s - -def write_files(): - global all_files - - run_commands = Config.get_config('run_commands', 0) - for f in all_files.files.values(): - f.write() - - for f in all_files.modified_files: - for a in all_files.action_assoc: - res = a[0].search(f) - if res: - s = substitute_re_result(res, a[1]) - if run_commands != '0': - log(_('%s modified so launched command: %s') % (f, s)) - cmd = commands.getstatusoutput(s) - if cmd[0] == 0: - log(cmd[1]) - else: - error(cmd[1]) - else: - log(_('%s modified so should have run command: %s') % (f, s)) - -def get_config_file(path, suffix=None): - global all_files - - return all_files.get_config_file(path, suffix) - -def add_config_assoc(regex, action): - global all_files - - return all_files.add_config_assoc(regex, action) - -def mkdir_p(path): - if not os.path.exists(path): - os.makedirs(path) - -# ConfigFile.py ends here diff --git a/share/Log.py b/share/Log.py deleted file mode 100644 index 061a5fb..0000000 --- a/share/Log.py +++ /dev/null @@ -1,54 +0,0 @@ -#--------------------------------------------------------------- -# Project : Mandriva Llinux -# Module : msec -# File : Log.py -# Version : $Id$ -# Author : Frederic Lepied -# Created On : Wed Dec 5 23:50:29 2001 -# Purpose : write log through syslog conforming to -# the Mandriva Linux guideline for the explanations -# in tools. Errors are reported to stderr. -#--------------------------------------------------------------- - -import syslog -import sys -import string -import Config - -_name = '' -_use_syslog = 1 - -def initlog(name, facility = syslog.LOG_AUTH): - global _name - global _use_syslog - - _use_syslog = (Config.get_config('log', 'syslog') == 'syslog') - - if _use_syslog: - syslog.openlog(name, 0, facility) - - _name = name - -def log(s, level = syslog.LOG_INFO): - global _use_syslog - - if _use_syslog: - for l in string.split(s, '\n'): - syslog.syslog(level, l) - else: - sys.stderr.write(s + '\n') - return 1 - -def closelog(): - global _use_syslog - - if _use_syslog: - syslog.closelog() - -def error(s): - global _name - - sys.stderr.write(_name + ': ' + s + '\n') - log(s) - -# Log.py ends here diff --git a/share/Makefile b/share/Makefile deleted file mode 100644 index 639324d..0000000 --- a/share/Makefile +++ /dev/null @@ -1,45 +0,0 @@ -#--------------------------------------------------------------- -# Project : Mandriva Linux -# Module : share -# File : Makefile -# Version : $Id$ -# Author : Frederic Lepied -# Created On : Sat Jan 26 20:17:55 2002 -#--------------------------------------------------------------- - -MAN=../man/C/mseclib.3 -PFILES=Config.py ConfigFile.py Log.py Perms.py compile.py draksec_help.py libmsec.py man.py - -all: mseclib.py compile man help.pm - -compile: - ./compile.py '/usr/share/msec/' *.py - rm -f msec.pyo - @for f in $(PFILES); do if grep -q print $$f; then echo "print statement in $$f:"; grep -Hn print $$f; exit 1; fi; done - -mseclib.py: libmsec.py shadow.py - rm -f $@ - ./shadow.py libmsec > $@ - -man: $(MAN) levels - -help.pm: libmsec.py draksec_help.py - rm -f $@ - ./draksec_help.py libmsec > $@ - -$(MAN): libmsec.py man.py - rm -f $@ - ./man.py libmsec > $@ - -levels: - for l in 0 1 2 3 4 5; do rm -f level.$$l; \ - ./msec.py -o log=stderr -o print=1 -o nolocal=1 $$l < /dev/null | sort > level.$$l; \ - done -clean: - rm -f *.pyc *.pyo mseclib.py *~ level.[0-5] help.pm - -# Local variables: -# mode: makefile -# End: -# -# Makefile ends here diff --git a/share/Perms.py b/share/Perms.py deleted file mode 100755 index ff4af73..0000000 --- a/share/Perms.py +++ /dev/null @@ -1,305 +0,0 @@ -#!/usr/bin/python -O -#--------------------------------------------------------------- -# Project : Mandriva Linux -# Module : msec -# File : Perms.py -# Version : $Id$ -# Author : Frederic Lepied -# Created On : Fri Dec 7 23:33:49 2001 -# Purpose : fix permissions and owner/group of files -# and directories. -#--------------------------------------------------------------- - -import glob -import re -import string -import os -import stat -import pwd -import grp -import Config -import sys -from Log import * -import gettext - -try: - cat = gettext.Catalog('msec') - _ = cat.gettext -except IOError: - _ = str - -comment_regex = re.compile('^\s*#|^\s*$') - -USER = {} -GROUP = {} -USERID = {} -GROUPID = {} - -def get_user_id(name): - try: - return USER[name] - except KeyError: - try: - USER[name] = pwd.getpwnam(name)[2] - except KeyError: - error(_('user name %s not found') % name) - USER[name] = -1 - return USER[name] - -def get_user_name(id): - try: - return USERID[id] - except KeyError: - try: - USERID[id] = pwd.getpwuid(id)[0] - except KeyError: - error(_('user name not found for id %d') % id) - USERID[id] = str(id) - return USERID[id] - -def get_group_id(name): - try: - return GROUP[name] - except KeyError: - try: - GROUP[name] = grp.getgrnam(name)[2] - except KeyError: - error(_('group name %s not found') % name) - GROUP[name] = -1 - return GROUP[name] - -def get_group_name(id): - try: - return GROUPID[id] - except KeyError: - try: - GROUPID[id] = grp.getgrgid(id)[0] - except KeyError: - error(_('group name not found for id %d') % id) - GROUPID[id] = str(id) - return GROUPID[id] - -# Build a regexp that matches all the non local filesystems -REGEXP_START = '^(' -REGEXP_END = ')' - -def build_non_localfs_regexp(): - # Allow to avoid this feature - if Config.get_config('all-local-files', '0') == '1': - return None - - try: - file = open('/proc/mounts', 'r') - except IOError: - error(_('Unable to check /proc/mounts. Assuming all file systems are local.')) - return None - - non_localfs = Config.get_config('non-local-fstypes', None) - if non_localfs: - non_localfs = string.split(non_localfs) - else: - non_localfs = ('nfs', 'codafs', 'smbfs') - - regexp = None - - for line in file.readlines(): - fields = string.split(line) - if fields[2] in non_localfs: - if regexp: - regexp = regexp + '|' + fields[1] - else: - regexp = REGEXP_START + fields[1] - - file.close() - - if not regexp: - return None - else: - return re.compile(regexp + REGEXP_END) - -# put the new perm/group/owner in the assoc variable according to the -# content of the path file. -assoc = {} - -def fix_perms(path, _interactive, force): - try: - file = open(path, 'r') - except IOError: - return - root = Config.get_config('root', '') - - fs_regexp = build_non_localfs_regexp() - - lineno = 0 - for line in file.readlines(): - lineno = lineno + 1 - - if comment_regex.search(line): - continue - - fields = re.split('\s*', line) - try: - mode_str = fields[2] - except IndexError: - error(_("%s: syntax error line %d") % (path, lineno)) - continue - - if mode_str == 'current': - perm = -1 - else: - try: - perm = int(mode_str, 8) - except ValueError: - error(_("%s: syntax error line %d") % (path, lineno)) - continue - - if fields[1] == 'current': - user = group = -1 - user_str = group_str = '' - else: - (user_str, group_str) = string.split(fields[1], '.') - if user_str != '': - user = get_user_id(user_str) - else: - user = -1 - if group_str != '': - group = get_group_id(group_str) - else: - group = -1 - - fieldcount = len(fields) - if fieldcount == 5: - if fields[3] == 'force': - mandatory = 1 - fieldcount = 4 - else: - mandatory = 0 - - if fieldcount == 4: - for f in glob.glob(fields[0]): - newperm = perm - f = os.path.realpath(f) - try: - full = os.lstat(f) - except OSError: - continue - - if fs_regexp and fs_regexp.search(f): - _interactive and log(_('Non local file: "%s". Nothing changed.') % fields[0]) - continue - - mode = stat.S_IMODE(full[stat.ST_MODE]) - - if newperm != -1 and stat.S_ISDIR(full[stat.ST_MODE]): - if newperm & 0400: - newperm = newperm | 0100 - if newperm & 0040: - newperm = newperm | 0010 - if newperm & 0004: - newperm = newperm | 0001 - - uid = full[stat.ST_UID] - gid = full[stat.ST_GID] - if f != '/' and f[-1] == '/': - f = f[:-1] - if f[-2:] == '/.': - f = f[:-2] - assoc[f] = (mode, uid, gid, newperm, user, group, user_str, group_str, mandatory or force) - else: - error(_('invalid syntax in %s line %d') % (path, lineno)) - file.close() - -# commit the changes to the files -def act(change): - for f in assoc.keys(): - (mode, uid, gid, newperm, user, group, user_str, group_str, mandatory) = assoc[f] - # if we don't change the security level, try not to lower the security - # if the user has changed it manually - if not change and not mandatory: - newperm = newperm & mode - if newperm != -1 and mode != newperm: - try: - os.chmod(f, newperm) - log(_('changed mode of %s from %o to %o') % (f, mode, newperm)) - except: - error('chmod %s %o: %s' % (f, newperm, str(sys.exc_value))) - if user != -1 and user != uid: - try: - os.chown(f, user, -1) - log(_('changed owner of %s from %s to %s') % (f, get_user_name(uid), user_str)) - except: - error('chown %s %s: %s' % (f, user, str(sys.exc_value))) - if group != -1 and group != gid: - try: - os.chown(f, -1, group) - log(_('changed group of %s from %s to %s') % (f, get_group_name(gid), group_str)) - except: - error('chgrp %s %s: %s' % (f, group, str(sys.exc_value))) - -def chmod(f, newperm): - try: - full = os.stat(f) - except OSError: - return 0 - mode = stat.S_IMODE(full[stat.ST_MODE]) - if stat.S_ISDIR(full[stat.ST_MODE]): - if newperm & 0400: - newperm = newperm | 0100 - if newperm & 0040: - newperm = newperm | 0010 - if newperm & 0004: - newperm = newperm | 0001 - if mode != newperm: - log(_('changed mode of %s from %o to %o') % (f, mode, newperm)) - try: - os.chmod(f, newperm) - except: - error('chmod %s %o: %s' % (f, newperm, str(sys.exc_value))) - return 1 - -if __name__ == '__main__': - import getopt - - _interactive = sys.stdin.isatty() - change = 0 - - # process the options - try: - (opt, args) = getopt.getopt(sys.argv[1:], 'co:', - ['change', 'option']) - except getopt.error: - error(_('Invalid option. Use %s (-o var=<val>...) ([0-5])') % sys.argv[0]) - sys.exit(1) - - for o in opt: - if o[0] == '-o' or o[0] == '--option': - pair = string.split(o[1], '=') - if len(pair) != 2: - error(_('Invalid option format %s %s: use -o var=<val>') % (o[0], o[1])) - sys.exit(1) - else: - Config.set_config(pair[0], pair[1]) - elif o[0] == '-c' or o[0] == '--change': - change = 1 - - # initlog must be done after processing the option because we can change - # the way to report log with options... - if _interactive: - import syslog - - initlog('msec', syslog.LOG_LOCAL1) - else: - initlog('msec') - - _interactive and log(_('Fixing owners and permissions of files and directories')) - - # process the files - fix_perms(args[0], _interactive, 0) - for p in args[1:]: - _interactive and log(_('Reading data from %s') % p) - fix_perms(p, _interactive, 1) - - # do the modifications - act(change) - -# Perms.py ends here diff --git a/share/README b/share/README deleted file mode 100644 index 4bb3846..0000000 --- a/share/README +++ /dev/null @@ -1,87 +0,0 @@ -****************** -Configurations files in /etc/security/msec/ -Shell scripts in /usr/share/msec. -****************** - -Suggestions & comments: -flepied@mandriva.com - -****************** -Doc of the rewritting in python: - - 0 1 2 3 4 5 -root umask 022 022 022 022 022 077 -shell timeout 0 0 0 0 3600 900 -deny services none none none none local all -su only for wheel grp no no no no no yes -user umask 022 022 022 022 077 077 -shell history size default default default default 10 10 -direct root login yes yes yes yes no no -remote root login yes yes yes yes no no -sulogin for single user no no no no yes yes -user list in [kg]dm yes yes yes yes no no -promisc check no no no no yes yes -ignore icmp echo no no no no yes yes -ignore broadcasted icmp echo no no no no yes yes -ignore bogus error responses no no no no yes yes -enable libsafe no no no no yes yes -allow reboot by user yes yes yes yes no no -allow crontab/at yes yes yes yes no no -password aging no no no no 60 30 -allow autologin yes yes yes no no no -console log no no no yes yes yes -issues yes yes yes local local no -ip spoofing protection no no no yes yes yes -dns spoofing protection no no no yes yes yes -log stange ip packets no no no yes yes yes -periodic security check no yes yes yes yes yes -allow X connections yes local local no no no -allow xauth from root yes yes yes yes no no -X server listen to tcp tcp tcp tcp local local -run msec by cron yes yes yes yes yes yes - -Periodic security checks by level: - - 0 1 2 3 4 5 -CHECK_SECURITY no yes yes yes yes yes -CHECK_PERMS no no no yes yes yes -CHECK_SUID_ROOT no no yes yes yes yes -CHECK_SUID_MD5 no no yes yes yes yes -CHECK_SGID no no yes yes yes yes -CHECK_WRITABLE no no yes yes yes yes -CHECK_UNOWNED no no no no yes yes -CHECK_PROMISC no no no no yes yes -CHECK_OPEN_PORT no no no yes yes yes -CHECK_PASSWD no no no yes yes yes -CHECK_SHADOW no no no yes yes yes -TTY_WARN no no no no yes yes -MAIL_WARN no no no yes yes yes -SYSLOG_WARN no no yes yes yes yes -RPM_CHECK no no no yes yes yes -CHKROOTKIT_CHECK no no no yes yes yes - -These variables are configured by the user: - -MAIL_USER the user to send the dayly reports. If not set, the email is -sent to root. - -PERM_LEVEL is used to determine which file to use to fix -permissions/owners/groups (from /usr/share/msec/perm.$PERM_LEVEL). If -not set, the SECURE_LEVEL is used instead. If the file -/etc/security/msec/perm.local exists, it's used too. The syntax for -each line if the following: - -<file specification> <owner> <permission> [force] - -<file specification> can be any glob to specify one or multiple -files/diretories. - -<owner> must be in the form <user>.<group> or <user>. (force only -user) or .<group> (force only group) or current (keep current user and -group). - -<permission> is an octal number representing the access rights or -current to keep the current permissions. - -If force is present as a 4th argument, it means that msec will enforce -the permission even if the previous permission was lower. diff --git a/share/compile.py b/share/compile.py deleted file mode 100755 index a325016..0000000 --- a/share/compile.py +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/python -O -############################################################################# -# File : compile.py -# Package : rpmlint -# Author : Frederic Lepied -# Created on : Sat Oct 23 23:40:21 1999 -# Version : $Id$ -# Purpose : byte compile all python files given in arguments. -############################################################################# - -import py_compile -import sys - -for f in sys.argv[2:]: - py_compile.compile(f, f+"o", sys.argv[1] + f) - -# compile.py ends here diff --git a/share/draksec_help.py b/share/draksec_help.py deleted file mode 100755 index b57ab86..0000000 --- a/share/draksec_help.py +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/python -#--------------------------------------------------------------- -# Project : Mandriva Linux -# Module : share -# File : draksec_help.py -# Version : $Id$ -# Author : Thierry Vignaud -# Created On : Sat Jan 26 17:38:39 2002 -# Purpose : loads a python module and creates a help hash -# for draksec. -#--------------------------------------------------------------- - -import sys -import imp -import inspect -import re - -header = '''package security::help; -# !! THIS FILE WAS AUTO-GENERATED BY draksec_help.py !! -# !! DO NOT MODIFY HERE, MODIFY IN THE *MSEC* CVS !! - -use strict; -use common; - -our %help = ( -''' - -footer = '''); -''' - -### strings used in the rewritting -function_str = ''' -'%s' => N("Arguments: %s -%s"), -''' - -### code -modulename = sys.argv[1] - -module = __import__(modulename) - -sys.stdout.write(header) - -clean = re.compile('^.[a-z].*\n', re.M) -clean2 = re.compile('^\n', re.M) -perl = re.compile('^([A-Z_0-9]*) (.*)$', re.M) - -for f in inspect.getmembers(module, inspect.isfunction): - (args, varargs, varkw, locals) = inspect.getargspec(f[1]) - doc = f[1].__doc__ - if doc and len(doc) > 2: - doc = doc[2:] - argspec = inspect.formatargspec(args, varargs, varkw, locals) + '\n' - if f[0] == 'set_security_conf': - doc = clean.sub('', doc) - doc = clean2.sub('', doc) - doc = perl.sub('\\1 => N("\\2"),', doc) - sys.stdout.write(doc) - else: - s = function_str % (f[0], argspec, doc) - sys.stdout.write(s) - -sys.stdout.write(footer) - -# draksec_help.py ends here diff --git a/share/libmsec.py b/share/libmsec.py deleted file mode 100644 index 2ef2e3c..0000000 --- a/share/libmsec.py +++ /dev/null @@ -1,1391 +0,0 @@ -#--------------------------------------------------------------- -# Project : Mandriva Linux -# Module : msec -# File : libmsec.py -# Version : $Id$ -# Author : Frederic Lepied -# Created On : Mon Dec 10 22:52:17 2001 -# Purpose : all access points of the msec utility. -#--------------------------------------------------------------- - -import ConfigFile -import Config -from Log import * - -import os -import grp -import Perms -import gettext -import pwd -import re -import string -import commands -import time -import traceback - -try: - cat = gettext.Catalog('msec') - _ = cat.gettext -except IOError: - _ = str - -SUFFIX='.msec' -_interactive=0 -_same_level=1 -FORCED = {} - -# list of config files - -ATALLOW = '/etc/at.allow' -AUTOLOGIN = '/etc/sysconfig/autologin' -BASTILLENOLOGIN = '/etc/bastille-no-login' -CRON = '/etc/cron.d/msec' -CRONALLOW = '/etc/cron.allow' -FSTAB = '/etc/fstab' -GDM = '/etc/pam.d/gdm' -GDMCONF = '/etc/X11/gdm/custom.conf' -HALT = '/usr/bin/halt' -HOSTCONF = '/etc/host.conf' -HOSTSDENY = '/etc/hosts.deny' -INITTAB = '/etc/inittab' -ISSUE = '/etc/issue' -ISSUENET = '/etc/issue.net' -KDE = '/etc/pam.d/kde' -KDMRC = '/usr/share/config/kdm/kdmrc' -LDSOPRELOAD = '/etc/ld.so.preload' -LILOCONF = '/etc/lilo.conf' -LOGINDEFS = '/etc/login.defs' -MENULST = '/boot/grub/menu.lst' -MSEC = '/etc/sysconfig/msec' -MSECBIN = '/usr/sbin/msec' -MSECCRON = '/etc/cron.hourly/msec' -MSEC_XINIT = '/etc/X11/xinit.d/msec' -OPASSWD = '/etc/security/opasswd' -PASSWD = '/etc/pam.d/passwd' -POWEROFF = '/usr/bin/poweroff' -REBOOT = '/usr/bin/reboot' -SECURETTY = '/etc/securetty' -SECURITYCONF = '/var/lib/msec/security.conf' -SECURITYCONF2 = '/etc/security/msec/security.conf' -SECURITYCRON = '/etc/cron.daily/msec' -SECURITYSH = '/usr/share/msec/security.sh' -SERVER = '/etc/security/msec/server' -SHADOW = '/etc/shadow' -SHUTDOWN = '/usr/bin/shutdown' -SHUTDOWNALLOW = '/etc/shutdown.allow' -SIMPLE_ROOT_AUTHEN = '/etc/pam.d/simple_root_authen' -SSHDCONFIG = '/etc/ssh/sshd_config' -STARTX = '/usr/bin/startx' -SU = '/etc/pam.d/su' -SYSCTLCONF = '/etc/sysctl.conf' -SYSLOGCONF = '/etc/syslog.conf' -SYSTEM_AUTH = '/etc/pam.d/system-auth' -XDM = '/etc/pam.d/xdm' -XSERVERS = '/etc/X11/xdm/Xservers' -EXPORT = '/root/.xauth/export' - -# constants to keep in sync with shadow.py -NONE=0 -ALL=1 -LOCAL=2 - -no=0 -yes=1 -without_password=2 - -ALL_LOCAL_NONE_TRANS = {ALL : 'ALL', NONE: 'NONE', LOCAL : 'LOCAL'} -YES_NO_TRANS = {yes : 'yes', no : 'no'} -ALLOW_ROOT_LOGIN_TRANS = {no : 'no', yes : 'yes', without_password : 'without_password'} - -# config files => actions - -ConfigFile.add_config_assoc(INITTAB, '/sbin/telinit q') -ConfigFile.add_config_assoc('/etc(?:/rc.d)?/init.d/(.+)', '[ -f /var/lock/subsys/@1 ] && @0 reload') -ConfigFile.add_config_assoc(SYSCTLCONF, '/sbin/sysctl -e -p /etc/sysctl.conf') -ConfigFile.add_config_assoc(SSHDCONFIG, '[ -f /var/lock/subsys/sshd ] && /etc/rc.d/init.d/sshd restart') -ConfigFile.add_config_assoc(LILOCONF, '[ `/usr/sbin/detectloader` = LILO ] && /sbin/lilo') -ConfigFile.add_config_assoc(SYSLOGCONF, '[ -f /var/lock/subsys/syslog ] && service syslog reload') -ConfigFile.add_config_assoc('^/etc/issue$', '/usr/bin/killall mingetty') - -# functions - -################################################################################ - -# The same_level function inspects the call stack in the 2 previous -# levels to see if a function is used that has been registered by -# force_val and if this is the case we act as if we were changing the -# security level to force the value to be used. -def same_level(): - 'D' - tb = traceback.extract_stack() - if FORCED.has_key(tb[-2][2]) or FORCED.has_key(tb[-3][2]): - return 0 - else: - return _same_level - -def changing_level(): - 'D' - global _same_level - _same_level=0 - -def force_val(name): - 'D' - global FORCED - FORCED[name] = 1 - -# configuration rules - -################################################################################ - -def set_secure_level(level): - msec = ConfigFile.get_config_file(MSEC) - - val = msec.get_shell_variable('SECURE_LEVEL') - - if not val or int(val) != level: - _interactive and log(_('Setting secure level to %s') % level) - msec.set_shell_variable('SECURE_LEVEL', level) - -################################################################################ - -def get_secure_level(): - 'D' - msec = ConfigFile.get_config_file(MSEC) - return msec.get_shell_variable('SECURE_LEVEL') - -################################################################################ - -def set_server_level(level): - _interactive and log(_('Setting server level to %s') % level) - securityconf = ConfigFile.get_config_file(SECURITYCONF2) - securityconf.set_shell_variable('SERVER_LEVEL', level) - -################################################################################ - -def get_server_level(): - 'D' - securityconf = ConfigFile.get_config_file(SECURITYCONF2) - level = securityconf.get_shell_variable('SERVER_LEVEL') - if level: return level - msec = ConfigFile.get_config_file(MSEC) - return msec.get_shell_variable('SECURE_LEVEL') - -################################################################################ - -def create_server_link(): - ''' If SERVER_LEVEL (or SECURE_LEVEL if absent) is greater than 3 -in /etc/security/msec/security.conf, creates the symlink /etc/security/msec/server -to point to /etc/security/msec/server.<SERVER_LEVEL>. The /etc/security/msec/server -is used by chkconfig --add to decide to add a service if it is present in the file -during the installation of packages.''' - level = get_server_level() - server = ConfigFile.get_config_file(SERVER) - if level in ('0', '1', '2', '3'): - _interactive and log(_('Allowing chkconfig --add from rpm')) - server.exists() and server.unlink() - else: - _interactive and log(_('Restricting chkconfig --add from rpm')) - server.symlink(SERVER + '.' + str(level)) - -create_server_link.arg_trans = YES_NO_TRANS - -################################################################################ - -STRING_TYPE = type('') - -# helper function for set_root_umask and set_user_umask -def set_umask(variable, umask, msg): - 'D' - msec = ConfigFile.get_config_file(MSEC) - - if type(umask) == STRING_TYPE: - umask = int(umask, 8) - - if msec.exists(): - val = msec.get_shell_variable(variable) - else: - val = None - - # don't lower security when not changing security level - if same_level(): - if val: - octal = umask | int(val, 8) - umask = '0%o' % octal - - if type(umask) != STRING_TYPE: - umask = '0%o' % umask - - if val != umask: - _interactive and log(_('Setting %s umask to %s') % (msg, umask)) - msec.set_shell_variable(variable, umask) - -def set_root_umask(umask): - ''' Set the root umask.''' - set_umask('UMASK_ROOT', umask, 'root') - -def set_user_umask(umask): - ''' Set the user umask.''' - set_umask('UMASK_USER', umask, 'users') - -################################################################################ - -# the listen_tcp argument is kept for backward compatibility -def allow_x_connections(arg, listen_tcp=None): - ''' Allow/Forbid X connections. First arg specifies what is done -on the client side: ALL (all connections are allowed), LOCAL (only -local connection) and NONE (no connection).''' - - msec = ConfigFile.get_config_file(MSEC_XINIT) - - val = msec.exists() and msec.get_match('/usr/bin/xhost\s*\+\s*([^#]*)') - - if val: - if val == '': - val = ALL - elif val == 'localhost': - val = LOCAL - else: - val = NONE - else: - val = NONE - - # don't lower security when not changing security level - if same_level(): - if val == NONE or (val == LOCAL and arg == ALL): - return - - if arg == ALL: - if val != arg: - _interactive and log(_('Allowing users to connect X server from everywhere')) - msec.exists() and msec.replace_line_matching('/usr/bin/xhost', '/usr/bin/xhost +', 1) - - elif arg == LOCAL: - if val != arg: - _interactive and log(_('Allowing users to connect X server from localhost')) - msec.exists() and msec.replace_line_matching('/usr/bin/xhost', '/usr/bin/xhost + localhost', 1) - - elif arg == NONE: - if val != arg: - _interactive and log(_('Restricting X server connection to the console user')) - msec.exists() and msec.remove_line_matching('/usr/bin/xhost', 1) - - else: - error(_('invalid allow_x_connections arg: %s') % arg) - return - -allow_x_connections.arg_trans=ALL_LOCAL_NONE_TRANS -allow_x_connections.one_arg = 1 - -################################################################################ - -STARTX_REGEXP = '(\s*serverargs=".*) -nolisten tcp(.*")' -XSERVERS_REGEXP = '(\s*[^#]+/usr/bin/X .*) -nolisten tcp(.*)' -GDMCONF_REGEXP = '(\s*command=.*/X.*?) -nolisten tcp(.*)$' -KDMRC_REGEXP = re.compile('(.*?)-nolisten tcp(.*)$') - -def allow_xserver_to_listen(arg): - ''' The argument specifies if clients are authorized to connect -to the X server on the tcp port 6000 or not.''' - - startx = ConfigFile.get_config_file(STARTX) - xservers = ConfigFile.get_config_file(XSERVERS) - gdmconf = ConfigFile.get_config_file(GDMCONF) - kdmrc = ConfigFile.get_config_file(KDMRC) - - val_startx = startx.exists() and startx.get_match(STARTX_REGEXP) - val_xservers = xservers.exists() and xservers.get_match(XSERVERS_REGEXP) - val_gdmconf = gdmconf.exists() and gdmconf.get_match(GDMCONF_REGEXP) - str = kdmrc.exists() and kdmrc.get_shell_variable('ServerArgsLocal', 'X-\*-Core', '^\s*$') - - if str: - val_kdmrc = KDMRC_REGEXP.search(str) - else: - val_kdmrc = None - - # don't lower security when not changing security level - if same_level(): - if val_startx and val_xservers and val_gdmconf and val_kdmrc: - return - - if arg: - if val_startx or val_xservers or val_gdmconf or val_kdmrc: - _interactive and log(_('Allowing the X server to listen to tcp connections')) - if not (same_level() and val_startx): - startx.exists() and startx.replace_line_matching(STARTX_REGEXP, '@1@2') - if not (same_level() and val_xservers): - xservers.exists() and xservers.replace_line_matching(XSERVERS_REGEXP, '@1@2', 0, 1) - if not (same_level() and val_gdmconf): - gdmconf.exists() and gdmconf.replace_line_matching(GDMCONF_REGEXP, '@1@2', 0, 1) - if not (same_level() and val_kdmrc): - kdmrc.exists() and kdmrc.replace_line_matching('^(ServerArgsLocal=.*?)-nolisten tcp(.*)$', '@1@2', 0, 0, 'X-\*-Core', '^\s*$') - else: - if not val_startx or not val_xservers or not val_gdmconf or not val_kdmrc: - _interactive and log(_('Forbidding the X server to listen to tcp connection')) - startx.exists() and not val_startx and startx.replace_line_matching('serverargs="(.*?)( -nolisten tcp)?"', 'serverargs="@1 -nolisten tcp"') - xservers.exists() and not val_xservers and xservers.replace_line_matching('(\s*[^#]+/usr/bin/X .*?)( -nolisten tcp)?$', '@1 -nolisten tcp', 0, 1) - gdmconf.exists() and not val_gdmconf and gdmconf.replace_line_matching('(\s*command=.*/X.*?)( -nolisten tcp)?$', '@1 -nolisten tcp', 0, 1) - kdmrc.exists() and not val_kdmrc and kdmrc.replace_line_matching('^(ServerArgsLocal=.*)( -nolisten tcp)?$', '@1 -nolisten tcp', 'ServerArgsLocal=-nolisten tcp', 0, 'X-\*-Core', '^\s*$') - -allow_xserver_to_listen.arg_trans = YES_NO_TRANS - -################################################################################ - -def set_shell_timeout(val): - ''' Set the shell timeout. A value of zero means no timeout.''' - - msec = ConfigFile.get_config_file(MSEC) - - if msec.exists(): - old = msec.get_shell_variable('TMOUT') - if old != None: - old = int(old) - else: - old = None - - # don't lower security when not changing security level - if same_level(): - if old != None and old > val: - return - - if old != val: - _interactive and log(_('Setting shell timeout to %s') % val) - msec.set_shell_variable('TMOUT', val) - -################################################################################ - -def set_shell_history_size(size): - ''' Set shell commands history size. A value of -1 means unlimited.''' - msec = ConfigFile.get_config_file(MSEC) - - if msec.exists(): - val = msec.get_shell_variable('HISTFILESIZE') - else: - val = None - - # don't lower security when not changing security level - if same_level(): - if val != None: - val = int(val) - if size == -1 or val < size: - return - - if size >= 0: - if val != size: - _interactive and log(_('Setting shell history size to %s') % size) - msec.set_shell_variable('HISTFILESIZE', size) - else: - if val != None: - _interactive and log(_('Removing limit on shell history size')) - msec.remove_line_matching('^HISTFILESIZE=') - -################################################################################ - -def set_win_parts_umask(umask): - ''' Set umask option for mounting vfat and ntfs partitions. A value of None means default umask.''' - fstab = ConfigFile.get_config_file(FSTAB) - - # don't lower security when not changing security level - if same_level(): - if umask != None: - return - - if umask == None: - fstab.replace_line_matching("(.*\s(vfat|ntfs)\s+)umask=\d+(\s.*)", "@1defaults@3", 0, 1) - fstab.replace_line_matching("(.*\s(vfat|ntfs)\s+)umask=\d+,(.*)", "@1@3", 0, 1) - fstab.replace_line_matching("(.*\s(vfat|ntfs)\s+\S+),umask=\d+(.*)", "@1@3", 0, 1) - else: - fstab.replace_line_matching("(.*\s(vfat|ntfs)\s+\S*)umask=\d+(.*)", "@1umask=0@3", 0, 1) - fstab.replace_line_matching("(.*\s(vfat|ntfs)\s+)(?!.*umask=)(\S+)(.*)", "@1@3,umask=0@4", 0, 1) - -################################################################################ - -def get_index(val, array): - for loop in range(0, len(array)): - if val == array[loop]: - return loop - return -1 - -################################################################################ -ALLOW_SHUTDOWN_VALUES = ('All', 'Root', 'None') -CTRALTDEL_REGEXP = '^ca::ctrlaltdel:/sbin/shutdown.*' -CONSOLE_HELPER = 'consolehelper' - -def allow_reboot(arg): - ''' Allow/Forbid reboot by the console user.''' - shutdownallow = ConfigFile.get_config_file(SHUTDOWNALLOW) - sysctlconf = ConfigFile.get_config_file(SYSCTLCONF) - kdmrc = ConfigFile.get_config_file(KDMRC) - gdmconf = ConfigFile.get_config_file(GDMCONF) - inittab = ConfigFile.get_config_file(INITTAB) - - val_shutdownallow = shutdownallow.exists() - val_sysctlconf = sysctlconf.exists() and sysctlconf.get_shell_variable('kernel.sysrq') - val_inittab = inittab.exists() and inittab.get_match(CTRALTDEL_REGEXP) - num = 0 - val = {} - for f in [SHUTDOWN, POWEROFF, REBOOT, HALT]: - val[f] = ConfigFile.get_config_file(f).exists() - if val[f]: - num = num + 1 - val_gdmconf = gdmconf.exists() and gdmconf.get_shell_variable('SystemMenu') - oldval_kdmrc = kdmrc.exists() and kdmrc.get_shell_variable('AllowShutdown', 'X-:\*-Core', '^\s*$') - if oldval_kdmrc: - oldval_kdmrc = get_index(oldval_kdmrc, ALLOW_SHUTDOWN_VALUES) - if arg: - val_kdmrc = 0 - else: - val_kdmrc = 2 - - # don't lower security when not changing security level - if same_level(): - if val_shutdownallow and val_sysctlconf == '0' and num == 0 and oldval_kdmrc >= val_kdmrc and val_gdmconf == 'false' and not val_inittab: - return - if oldval_kdmrc > val_kdmrc: - val_kdmrc = oldval_kdmrc - - if arg: - _interactive and log(_('Allowing reboot to the console user')) - if not (same_level() and val_shutdownallow): - shutdownallow.exists() and shutdownallow.move(SUFFIX) - for f in [SHUTDOWN, POWEROFF, REBOOT, HALT]: - cfg = ConfigFile.get_config_file(f) - if not (same_level() and not val[f]): - cfg.exists() or cfg.symlink(CONSOLE_HELPER) - if not (same_level() and val_sysctlconf == '0'): - sysctlconf.set_shell_variable('kernel.sysrq', 1) - if not same_level() and val_gdmconf == 'false': - gdmconf.exists() and gdmconf.set_shell_variable('SystemMenu', 'true', '\[greeter\]', '^\s*$') - if not (same_level() and not val_inittab): - inittab.replace_line_matching(CTRALTDEL_REGEXP, 'ca::ctrlaltdel:/sbin/shutdown -t3 -r now', 1) - else: - _interactive and log(_('Forbidding reboot to the console user')) - ConfigFile.get_config_file(SHUTDOWNALLOW, SUFFIX).touch() - for f in [SHUTDOWN, POWEROFF, REBOOT, HALT]: - ConfigFile.get_config_file(f).unlink() - sysctlconf.set_shell_variable('kernel.sysrq', 0) - gdmconf.exists() and gdmconf.set_shell_variable('SystemMenu', 'false', '\[greeter\]', '^\s*$') - inittab.remove_line_matching(CTRALTDEL_REGEXP) - - kdmrc.exists() and kdmrc.set_shell_variable('AllowShutdown', ALLOW_SHUTDOWN_VALUES[val_kdmrc], 'X-:\*-Core', '^\s*$') - -allow_reboot.arg_trans = YES_NO_TRANS - -################################################################################ -SHOW_USERS_VALUES = ('NotHidden', 'Selected') - -def allow_user_list(arg): - ''' Allow/Forbid the list of users on the system on display managers (kdm and gdm).''' - kdmrc = ConfigFile.get_config_file(KDMRC) - gdmconf = ConfigFile.get_config_file(GDMCONF) - - oldval_gdmconf = gdmconf.exists() and gdmconf.get_shell_variable('Browser') - oldval_kdmrc = kdmrc.exists() and kdmrc.get_shell_variable('ShowUsers', 'X-\*-Greeter', '^\s*$') - if oldval_kdmrc: - oldval_kdmrc = get_index(oldval_kdmrc, SHOW_USERS_VALUES) - - if arg: - msg = 'Allowing the listing of users in display managers' - val_kdmrc = 0 - val_gdmconf = 'true' - else: - msg = 'Disabling the listing of users in display managers' - val_kdmrc = 1 - val_gdmconf = 'false' - - # don't lower security when not changing security level - if same_level(): - if oldval_kdmrc >= val_kdmrc and oldval_gdmconf == 'false': - return - if oldval_kdmrc > val_kdmrc: - val_kdmrc = oldval_kdmrc - if oldval_gdmconf == 'false': - val_gdmconf = 'false' - - if (gdmconf.exists() and oldval_gdmconf != val_gdmconf) or (kdmrc.exists() and oldval_kdmrc != val_kdmrc): - _interactive and log(_(msg)) - oldval_kdmrc != val_gdmconf and kdmrc.exists() and kdmrc.set_shell_variable('ShowUsers', SHOW_USERS_VALUES[val_kdmrc], 'X-\*-Greeter', '^\s*$') - oldval_gdmconf != val_gdmconf and gdmconf.exists() and gdmconf.set_shell_variable('Browser', val_gdmconf) - -allow_user_list.arg_trans = YES_NO_TRANS - -################################################################################ - -def allow_root_login(arg): - ''' Allow/Forbid direct root login.''' - securetty = ConfigFile.get_config_file(SECURETTY) - kde = ConfigFile.get_config_file(KDE) - gdm = ConfigFile.get_config_file(GDM) - gdmconf = ConfigFile.get_config_file(GDMCONF) - xdm = ConfigFile.get_config_file(XDM) - - val = {} - val[kde] = kde.exists() and kde.get_match('auth required (?:/lib/security/)?pam_listfile.so onerr=succeed item=user sense=deny file=/etc/bastille-no-login') - val[gdm] = gdm.exists() and gdm.get_match('auth required (?:/lib/security/)?pam_listfile.so onerr=succeed item=user sense=deny file=/etc/bastille-no-login') - val[xdm] = xdm.exists() and xdm.get_match('auth required (?:/lib/security/)?pam_listfile.so onerr=succeed item=user sense=deny file=/etc/bastille-no-login') - num = 0 - for n in range(1, 7): - s = 'tty' + str(n) - if securetty.get_match(s): - num = num + 1 - val[s] = 1 - else: - val[s] = 0 - s = 'vc/' + str(n) - if securetty.get_match(s): - num = num + 1 - val[s] = 1 - else: - val[s] = 0 - - # don't lower security when not changing security level - if same_level(): - if (not kde.exists() or val[kde]) and (not gdm.exists() or val[gdm]) and (not xdm.exists() or val[xdm]) and num == 12: - return - - if arg: - if val[kde] or val[gdm] or val[xdm] or num != 12: - _interactive and log(_('Allowing direct root login')) - gdmconf.exists() and gdmconf.set_shell_variable('ConfigAvailable', 'true', '\[greeter\]', '^\s*') - - - for cnf in (kde, gdm, xdm): - if not (same_level() and val[cnf]): - cnf.exists() and cnf.remove_line_matching('^auth\s*required\s*(?:/lib/security/)?pam_listfile.so.*bastille-no-login', 1) - - for n in range(1, 7): - s = 'tty' + str(n) - if not (same_level() and not val[s]): - securetty.replace_line_matching(s, s, 1) - s = 'vc/' + str(n) - if not (same_level() and not val[s]): - securetty.replace_line_matching(s, s, 1) - else: - gdmconf.exists() and gdmconf.set_shell_variable('ConfigAvailable', 'false', '\[greeter\]', '^\s*') - if (kde.exists() and not val[kde]) or (gdm.exists() and not val[gdm]) or (xdm.exists() and not val[xdm]) or num > 0: - _interactive and log(_('Forbidding direct root login')) - - bastillenologin = ConfigFile.get_config_file(BASTILLENOLOGIN) - bastillenologin.replace_line_matching('^\s*root', 'root', 1) - - for cnf in (kde, gdm, xdm): - cnf.exists() and (cnf.replace_line_matching('^auth\s*required\s*(?:/lib/security/)?pam_listfile.so.*bastille-no-login', 'auth required pam_listfile.so onerr=succeed item=user sense=deny file=/etc/bastille-no-login') or \ - cnf.insert_at(0, 'auth required pam_listfile.so onerr=succeed item=user sense=deny file=/etc/bastille-no-login')) - securetty.remove_line_matching('.+', 1) - -allow_root_login.arg_trans = YES_NO_TRANS - -PERMIT_ROOT_LOGIN_REGEXP = '^\s*PermitRootLogin\s+(no|yes|without-password|forced-commands-only)' - -################################################################################ - -def allow_remote_root_login(arg): - ''' Allow/Forbid remote root login via sshd. You can specify -yes, no and without-password. See sshd_config(5) man page for more -information.''' - sshd_config = ConfigFile.get_config_file(SSHDCONFIG) - - if sshd_config.exists(): - val = sshd_config.get_match(PERMIT_ROOT_LOGIN_REGEXP, '@1') - else: - val = None - - # don't lower security when not changing security level - if same_level(): - if val == 'no': - return - if val == 'forced-commands-only': - return - - if val == 'yes': - val = yes - elif val == 'no': - val = no - elif val == 'without-password': - val = without_password - else: - val = yes - - if val != arg: - if arg == yes: - _interactive and log(_('Allowing remote root login')) - sshd_config.exists() and sshd_config.replace_line_matching(PERMIT_ROOT_LOGIN_REGEXP, - 'PermitRootLogin yes', 1) - elif arg == no: - _interactive and log(_('Forbidding remote root login')) - sshd_config.exists() and sshd_config.replace_line_matching(PERMIT_ROOT_LOGIN_REGEXP, - 'PermitRootLogin no', 1) - elif arg == without_password: - _interactive and log(_('Allowing remote root login only by passphrase')) - sshd_config.exists() and sshd_config.replace_line_matching(PERMIT_ROOT_LOGIN_REGEXP, - 'PermitRootLogin without-password', 1) - -allow_remote_root_login.arg_trans = ALLOW_ROOT_LOGIN_TRANS - -################################################################################ - -def enable_pam_wheel_for_su(arg): - ''' Enabling su only from members of the wheel group or allow su from any user.''' - su = ConfigFile.get_config_file(SU) - - val = su.exists() and su.get_match('^auth\s+required\s+(?:/lib/security/)?pam_wheel.so\s+use_uid\s*$') - - # don't lower security when not changing security level - if same_level(): - if val: - return - - if arg: - if not val: - _interactive and log(_('Allowing su only from wheel group members')) - try: - ent = grp.getgrnam('wheel') - except KeyError: - error(_('no wheel group')) - return - members = ent[3] - if members == [] or members == ['root']: - _interactive and error(_('wheel group is empty')) - return - su.exists() and (su.replace_line_matching('^auth\s+required\s+(?:/lib/security/)?pam_wheel.so\s+use_uid\s*$', - 'auth required pam_wheel.so use_uid') or \ - su.insert_after('^auth\s+required', - 'auth required pam_wheel.so use_uid')) - else: - if val: - _interactive and log(_('Allowing su for all')) - su.exists() and su.remove_line_matching('^auth\s+required\s+(?:/lib/security/)?pam_wheel.so\s+use_uid\s*$') - -enable_pam_wheel_for_su.arg_trans = YES_NO_TRANS - -################################################################################ - -SUCCEED_MATCH = '^auth\s+sufficient\s+pam_succeed_if.so\s+use_uid\s+user\s+ingroup\s+wheel\s*$' -SUCCEED_LINE = 'auth sufficient pam_succeed_if.so use_uid user ingroup wheel' - -def enable_pam_root_from_wheel(arg): - ''' Allow root access without password for the members of the wheel group.''' - su = ConfigFile.get_config_file(SU) - simple = ConfigFile.get_config_file(SIMPLE_ROOT_AUTHEN) - - if not su.exists(): - return - - val = su.get_match(SUCCEED_MATCH) - - if simple.exists(): - val_simple = simple.get_match(SUCCEED_MATCH) - else: - val_simple = False - - # don't lower security when not changing security level - if same_level(): - if not val and not val_simple: - return - - if arg: - if not val or (simple.exists() and not val_simple): - _interactive and log(_('Allowing transparent root access for wheel group members')) - if not val: - su.insert_before('^auth\s+required', SUCCEED_LINE) - if simple.exists() and not val_simple: - simple.insert_before('^auth\s+required', SUCCEED_LINE) - else: - if val or (simple.exists() and val_simple): - _interactive and log(_('Disabling transparent root access for wheel group members')) - if val: - su.remove_line_matching(SUCCEED_MATCH) - if simple.exists() and val_simple: - simple.remove_line_matching(SUCCEED_MATCH) - -enable_pam_root_from_wheel.arg_trans = YES_NO_TRANS - -################################################################################ - -def allow_issues(arg): - ''' If \\fIarg\\fP = ALL allow /etc/issue and /etc/issue.net to exist. If \\fIarg\\fP = NONE no issues are -allowed else only /etc/issue is allowed.''' - issue = ConfigFile.get_config_file(ISSUE, SUFFIX) - issuenet = ConfigFile.get_config_file(ISSUENET, SUFFIX) - - val = issue.exists(1) - valnet = issuenet.exists(1) - - # don't lower security when not changing security level - if same_level(): - if not val and not valnet: - return - if arg == ALL and not valnet: - return - - if arg == ALL: - if not (val and valnet): - _interactive and log(_('Allowing network pre-login messages')) - issue.exists() and issue.get_lines() - issuenet.exists() and issuenet.get_lines() - else: - if arg == NONE: - if val: - _interactive and log(_('Disabling pre-login message')) - issue.exists(1) and issue.move(SUFFIX) and issue.modified() - else: - if not val: - _interactive and log(_('Allowing pre-login message')) - issue.exists() and issue.get_lines() - if valnet: - _interactive and log(_('Disabling network pre-login message')) - issuenet.exists(1) and issuenet.move(SUFFIX) - -allow_issues.arg_trans = ALL_LOCAL_NONE_TRANS - -################################################################################ - -def allow_autologin(arg): - ''' Allow/Forbid autologin.''' - autologin = ConfigFile.get_config_file(AUTOLOGIN) - - if autologin.exists(): - val = autologin.get_shell_variable('AUTOLOGIN') - else: - val = None - - # don't lower security when not changing security level - if same_level(): - if val == 'no': - return - - if arg: - if val != 'yes': - _interactive and log(_('Allowing autologin')) - autologin.exists() and autologin.set_shell_variable('AUTOLOGIN', 'yes') - else: - if val != 'no': - _interactive and log(_('Forbidding autologin')) - autologin.exists() and autologin.set_shell_variable('AUTOLOGIN', 'no') - -allow_autologin.arg_trans = YES_NO_TRANS - -################################################################################ - -def password_loader(value): - 'D' - _interactive and log(_('Activating password in boot loader')) - liloconf = ConfigFile.get_config_file(LILOCONF) - liloconf.exists() and (liloconf.replace_line_matching('^password=', 'password="' + value + '"', 0, 1) or \ - liloconf.insert_after('^boot=', 'password="' + value + '"')) and \ - Perms.chmod(liloconf.path, 0600) - # TODO encrypt password in grub - menulst = ConfigFile.get_config_file(MENULST) - menulst.exists() and (menulst.replace_line_matching('^password\s', 'password "' + value + '"') or \ - menulst.insert_at(0, 'password "' + value + '"')) and \ - Perms.chmod(menulst.path, 0600) - # TODO add yaboot support - -################################################################################ - -def nopassword_loader(): - 'D' - _interactive and log(_('Removing password in boot loader')) - liloconf = ConfigFile.get_config_file(LILOCONF) - liloconf.exists() and liloconf.remove_line_matching('^password=', 1) - menulst = ConfigFile.get_config_file(MENULST) - menulst.exists() and menulst.remove_line_matching('^password\s') - -################################################################################ - -def enable_console_log(arg, expr='*.*', dev='tty12'): - ''' Enable/Disable syslog reports to console 12. \\fIexpr\\fP is the -expression describing what to log (see syslog.conf(5) for more details) and -dev the device to report the log.''' - - syslogconf = ConfigFile.get_config_file(SYSLOGCONF) - - if syslogconf.exists(): - val = syslogconf.get_match('\s*[^#]+/dev/([^ ]+)', '@1') - else: - val = None - - # don't lower security when not changing security level - if same_level(): - if val: - return - - if arg: - if dev != val: - _interactive and log(_('Enabling log on console')) - syslogconf.exists() and syslogconf.replace_line_matching('\s*[^#]+/dev/', expr + ' /dev/' + dev, 1) - else: - if val != None: - _interactive and log(_('Disabling log on console')) - syslogconf.exists() and syslogconf.remove_line_matching('\s*[^#]+/dev/') - -enable_console_log.arg_trans = YES_NO_TRANS - -CRON_ENTRY = '*/1 * * * * root /usr/share/msec/promisc_check.sh' -CRON_REGEX = '[^#]+/usr/share/msec/promisc_check.sh' - -################################################################################ - -def enable_promisc_check(arg): - ''' Activate/Disable ethernet cards promiscuity check.''' - cron = ConfigFile.get_config_file(CRON) - - val = cron.exists() and cron.get_match(CRON_REGEX) - - # don't lower security when not changing security level - if same_level(): - if val == CRON_ENTRY: - return - - if arg: - if val != CRON_ENTRY: - _interactive and log(_('Activating periodic promiscuity check')) - cron.replace_line_matching(CRON_REGEX, CRON_ENTRY, 1) - else: - if val: - _interactive and log(_('Disabling periodic promiscuity check')) - cron.remove_line_matching('[^#]+/usr/share/msec/promisc_check.sh') - -enable_promisc_check.arg_trans = YES_NO_TRANS - -################################################################################ - -def enable_security_check(arg): - ''' Activate/Disable daily security check.''' - cron = ConfigFile.get_config_file(CRON) - cron.remove_line_matching('[^#]+/usr/share/msec/security.sh') - - securitycron = ConfigFile.get_config_file(SECURITYCRON) - - val = securitycron.exists() - - # don't lower security when not changing security level - if same_level(): - if val: - return - - if arg: - if not val: - _interactive and log(_('Activating daily security check')) - securitycron.symlink(SECURITYSH) - else: - if val: - _interactive and log(_('Disabling daily security check')) - securitycron.unlink() - -enable_security_check.arg_trans = YES_NO_TRANS - -################################################################################ - -ALL_REGEXP = '^ALL:ALL:DENY' -ALL_LOCAL_REGEXP = '^ALL:ALL EXCEPT 127\.0\.0\.1:DENY' -def authorize_services(arg): - ''' Authorize all services controlled by tcp_wrappers (see hosts.deny(5)) if \\fIarg\\fP = ALL. Only local ones -if \\fIarg\\fP = LOCAL and none if \\fIarg\\fP = NONE. To authorize the services you need, use /etc/hosts.allow -(see hosts.allow(5)).''' - hostsdeny = ConfigFile.get_config_file(HOSTSDENY) - - if hostsdeny.exists(): - if hostsdeny.get_match(ALL_REGEXP): - val = NONE - elif hostsdeny.get_match(ALL_LOCAL_REGEXP): - val = LOCAL - else: - val = ALL - else: - val = ALL - - # don't lower security when not changing security level - if same_level(): - if val == NONE or (val == LOCAL and arg == ALL): - return - - if arg == ALL: - if arg != val: - _interactive and log(_('Authorizing all services')) - hostsdeny.remove_line_matching(ALL_REGEXP, 1) - hostsdeny.remove_line_matching(ALL_LOCAL_REGEXP, 1) - elif arg == NONE: - if arg != val: - _interactive and log(_('Disabling all services')) - hostsdeny.remove_line_matching('^ALL:ALL EXCEPT 127\.0\.0\.1:DENY', 1) - hostsdeny.replace_line_matching('^ALL:ALL:DENY', 'ALL:ALL:DENY', 1) - elif arg == LOCAL: - if arg != val: - _interactive and log(_('Disabling non local services')) - hostsdeny.remove_line_matching(ALL_REGEXP, 1) - hostsdeny.replace_line_matching(ALL_LOCAL_REGEXP, 'ALL:ALL EXCEPT 127.0.0.1:DENY', 1) - else: - error(_('authorize_services invalid argument: %s') % arg) - -authorize_services.arg_trans = ALL_LOCAL_NONE_TRANS - -################################################################################ - -def boolean2bit(bool): - if bool: - return 1 - else: - return 0 - -# helper function for enable_ip_spoofing_protection, accept_icmp_echo, accept_broadcasted_icmp_echo, -# accept_bogus_error_responses and enable_log_strange_packets. -def set_zero_one_variable(file, variable, value, secure_value, one_msg, zero_msg): - 'D' - f = ConfigFile.get_config_file(file) - - if f.exists(): - val = f.get_shell_variable(variable) - if val: - val = int(val) - else: - val = None - - # don't lower security when not changing security level - if same_level(): - if val == secure_value: - return - - if value != val: - if value: - msg = _(one_msg) - else: - msg = _(zero_msg) - - _interactive and log(msg) - f.set_shell_variable(variable, boolean2bit(value)) - -################################################################################ - -# the alert argument is kept for backward compatibility -def enable_ip_spoofing_protection(arg, alert=1): - ''' Enable/Disable IP spoofing protection.''' - set_zero_one_variable(SYSCTLCONF, 'net.ipv4.conf.all.rp_filter', arg, 1, 'Enabling ip spoofing protection', 'Disabling ip spoofing protection') - -enable_ip_spoofing_protection.arg_trans = YES_NO_TRANS -enable_ip_spoofing_protection.one_arg = 1 - -################################################################################ - -def enable_dns_spoofing_protection(arg, alert=1): - ''' Enable/Disable name resolution spoofing protection. If -\\fIalert\\fP is true, also reports to syslog.''' - hostconf = ConfigFile.get_config_file(HOSTCONF) - - val = hostconf.exists() and hostconf.get_match('nospoof\s+on') - - # don't lower security when not changing security level - if same_level(): - if val: - return - - if arg: - if not val: - _interactive and log(_('Enabling name resolution spoofing protection')) - hostconf.replace_line_matching('nospoof', 'nospoof on', 1) - hostconf.replace_line_matching('spoofalert', 'spoofalert on', (alert != 0)) - else: - if val: - _interactive and log(_('Disabling name resolution spoofing protection')) - hostconf.remove_line_matching('nospoof') - hostconf.remove_line_matching('spoofalert') - -enable_dns_spoofing_protection.arg_trans = YES_NO_TRANS - -################################################################################ - -def accept_icmp_echo(arg): - ''' Accept/Refuse icmp echo.''' - set_zero_one_variable(SYSCTLCONF, 'net.ipv4.icmp_echo_ignore_all', not arg, 1, 'Ignoring icmp echo', 'Accepting icmp echo') - -accept_icmp_echo.arg_trans = YES_NO_TRANS - -################################################################################ - -def accept_broadcasted_icmp_echo(arg): - ''' Accept/Refuse broadcasted icmp echo.''' - set_zero_one_variable(SYSCTLCONF, 'net.ipv4.icmp_echo_ignore_broadcasts', not arg, 1, 'Ignoring broadcasted icmp echo', 'Accepting broadcasted icmp echo') - -accept_broadcasted_icmp_echo.arg_trans = YES_NO_TRANS - -################################################################################ - -def accept_bogus_error_responses(arg): - ''' Accept/Refuse bogus IPv4 error messages.''' - set_zero_one_variable(SYSCTLCONF, 'net.ipv4.icmp_ignore_bogus_error_responses', not arg, 1, 'Ignoring bogus icmp error responses', 'Accepting bogus icmp error responses') - -accept_bogus_error_responses.arg_trans = YES_NO_TRANS - -################################################################################ - -def enable_log_strange_packets(arg): - ''' Enable/Disable the logging of IPv4 strange packets.''' - set_zero_one_variable(SYSCTLCONF, 'net.ipv4.conf.all.log_martians', arg, 1, 'Enabling logging of strange packets', 'Disabling logging of strange packets') - -enable_log_strange_packets.arg_trans = YES_NO_TRANS - -################################################################################ - -def enable_libsafe(arg): - ''' Enable/Disable libsafe if libsafe is found on the system.''' - - ldsopreload = ConfigFile.get_config_file(LDSOPRELOAD) - - val = ldsopreload.exists() and ldsopreload.get_match('/lib/libsafe.so.2') - - # don't lower security when not changing security level - if same_level(): - if val: - return - - if arg: - if not val: - if os.path.exists(Config.get_config('root', '') + '/lib/libsafe.so.2'): - _interactive and log(_('Enabling libsafe')) - ldsopreload.replace_line_matching('[^#]*libsafe', '/lib/libsafe.so.2', 1) - else: - if val: - _interactive and log(_('Disabling libsafe')) - ldsopreload.remove_line_matching('[^#]*libsafe') - -enable_libsafe.arg_trans = YES_NO_TRANS - -################################################################################ - -LENGTH_REGEXP = re.compile('^(password\s+required\s+(?:/lib/security/)?pam_cracklib.so.*?)\sminlen=([0-9]+)\s(.*)') -NDIGITS_REGEXP = re.compile('^(password\s+required\s+(?:/lib/security/)?pam_cracklib.so.*?)\sdcredit=([0-9]+)\s(.*)') -UCREDIT_REGEXP = re.compile('^(password\s+required\s+(?:/lib/security/)?pam_cracklib.so.*?)\sucredit=([0-9]+)\s(.*)') - -def password_length(length, ndigits=0, nupper=0): - ''' Set the password minimum length and minimum number of digit and minimum number of capitalized letters.''' - - passwd = ConfigFile.get_config_file(SYSTEM_AUTH) - - val_length = val_ndigits = val_ucredit = 999999 - - if passwd.exists(): - val_length = passwd.get_match(LENGTH_REGEXP, '@2') - if val_length: - val_length = int(val_length) - - val_ndigits = passwd.get_match(NDIGITS_REGEXP, '@2') - if val_ndigits: - val_ndigits = int(val_ndigits) - - val_ucredit = passwd.get_match(UCREDIT_REGEXP, '@2') - if val_ucredit: - val_ucredit = int(val_ucredit) - - # don't lower security when not changing security level - if same_level(): - if val_length > length and val_ndigits > ndigits and val_ucredit > nupper: - return - - if val_length > length: - length = val_length - - if val_ndigits > ndigits: - ndigits = val_ndigits - - if val_ucredit > nupper: - nupper = val_ucredit - - if passwd.exists() and (val_length != length or val_ndigits != ndigits or val_ucredit != nupper): - _interactive and log(_('Setting minimum password length %d') % length) - (passwd.replace_line_matching(LENGTH_REGEXP, - '@1 minlen=%s @3' % length) or \ - passwd.replace_line_matching('^password\s+required\s+(?:/lib/security/)?pam_cracklib.so.*', - '@0 minlen=%s ' % length)) - - (passwd.replace_line_matching(NDIGITS_REGEXP, - '@1 dcredit=%s @3' % ndigits) or \ - passwd.replace_line_matching('^password\s+required\s+(?:/lib/security/)?pam_cracklib.so.*', - '@0 dcredit=%s ' % ndigits)) - - (passwd.replace_line_matching(UCREDIT_REGEXP, - '@1 ucredit=%s @3' % nupper) or \ - passwd.replace_line_matching('^password\s+required\s+(?:/lib/security/)?pam_cracklib.so.*', - '@0 ucredit=%s ' % nupper)) - -################################################################################ - -PASSWORD_REGEXP = '^\s*auth\s+sufficient\s+(?:/lib/security/)?pam_permit.so' -def enable_password(arg): - ''' Use password to authenticate users.''' - system_auth = ConfigFile.get_config_file(SYSTEM_AUTH) - - val = system_auth.exists() and system_auth.get_match(PASSWORD_REGEXP) - - # don't lower security when not changing security level - if same_level(): - if not val: - return - - if arg: - if val: - _interactive and log(_('Using password to authenticate users')) - system_auth.remove_line_matching(PASSWORD_REGEXP) - else: - if not val: - _interactive and log(_('Don\'t use password to authenticate users')) - system_auth.replace_line_matching(PASSWORD_REGEXP, 'auth sufficient pam_permit.so') or \ - system_auth.insert_before('auth\s+sufficient', 'auth sufficient pam_permit.so') - -enable_password.arg_trans = YES_NO_TRANS - -################################################################################ - -UNIX_REGEXP = re.compile('(^\s*password\s+sufficient\s+(?:/lib/security/)?pam_unix.so.*)\sremember=([0-9]+)(.*)') - -def password_history(arg): - ''' Set the password history length to prevent password reuse.''' - system_auth = ConfigFile.get_config_file(SYSTEM_AUTH) - - if system_auth.exists(): - val = system_auth.get_match(UNIX_REGEXP, '@2') - - if val and val != '': - val = int(val) - else: - val = 0 - else: - val = 0 - - # don't lower security when not changing security level - if same_level(): - if val >= arg: - return - - if arg != val: - if arg > 0: - _interactive and log(_('Setting password history to %d.') % arg) - system_auth.replace_line_matching(UNIX_REGEXP, '@1 remember=%d@3' % arg) or \ - system_auth.replace_line_matching('(^\s*password\s+sufficient\s+(?:/lib/security/)?pam_unix.so.*)', '@1 remember=%d' % arg) - opasswd = ConfigFile.get_config_file(OPASSWD) - opasswd.exists() or opasswd.touch() - else: - _interactive and log(_('Disabling password history')) - system_auth.replace_line_matching(UNIX_REGEXP, '@1@3') - -################################################################################ - -SULOGIN_REGEXP = '~~:S:wait:/sbin/sulogin' -def enable_sulogin(arg): - ''' Enable/Disable sulogin(8) in single user level.''' - inittab = ConfigFile.get_config_file(INITTAB) - - val = inittab.exists() and inittab.get_match(SULOGIN_REGEXP) - - # don't lower security when not changing security level - if same_level(): - if val: - return - - if arg: - if not val: - _interactive and log(_('Enabling sulogin in single user runlevel')) - inittab.replace_line_matching('[^#]+:S:', '~~:S:wait:/sbin/sulogin', 1) - else: - if val: - _interactive and log(_('Disabling sulogin in single user runlevel')) - inittab.remove_line_matching('~~:S:wait:/sbin/sulogin') - -enable_sulogin.arg_trans = YES_NO_TRANS - -################################################################################ - -def enable_msec_cron(arg): - ''' Enable/Disable msec hourly security check.''' - mseccron = ConfigFile.get_config_file(MSECCRON) - - val = mseccron.exists() - - # don't lower security when not changing security level - if same_level(): - if val: - return - - if arg: - if arg != val: - _interactive and log(_('Enabling msec periodic runs')) - mseccron.symlink(MSECBIN) - else: - if arg != val: - _interactive and log(_('Disabling msec periodic runs')) - mseccron.unlink() - -enable_msec_cron.arg_trans = YES_NO_TRANS - -################################################################################ - -def enable_at_crontab(arg): - ''' Enable/Disable crontab and at for users. Put allowed users in /etc/cron.allow and /etc/at.allow -(see man at(1) and crontab(1)).''' - cronallow = ConfigFile.get_config_file(CRONALLOW) - atallow = ConfigFile.get_config_file(ATALLOW) - - val_cronallow = cronallow.exists() and cronallow.get_match('root') - val_atallow = atallow.exists() and atallow.get_match('root') - - # don't lower security when not changing security level - if same_level(): - if val_cronallow and val_atallow: - return - - if arg: - if val_cronallow or val_atallow: - _interactive and log(_('Enabling crontab and at')) - if not (same_level() and val_cronallow): - cronallow.exists() and cronallow.move(SUFFIX) - if not (same_level() and val_atallow): - atallow.exists() and atallow.move(SUFFIX) - else: - if not val_cronallow or not val_atallow: - _interactive and log(_('Disabling crontab and at')) - cronallow.replace_line_matching('root', 'root', 1) - atallow.replace_line_matching('root', 'root', 1) - -enable_at_crontab.arg_trans = YES_NO_TRANS - -################################################################################ - -maximum_regex = re.compile('^Maximum.*:\s*([0-9]+|-1)', re.MULTILINE) -inactive_regex = re.compile('^(Inactive|Password inactive\s*):\s*(-?[0-9]+|never)', re.MULTILINE) -no_aging_list = [] - -def no_password_aging_for(name): - '''D Add the name as an exception to the handling of password aging by msec. -Name must be put between '. Msec will then no more manage password aging for -name so you have to use chage(1) to manage it by hand.''' - no_aging_list.append(name) - -def password_aging(max, inactive=-1): - ''' Set password aging to \\fImax\\fP days and delay to change to \\fIinactive\\fP.''' - uid_min = 500 - _interactive and log(_('Setting password maximum aging for new user to %d') % max) - logindefs = ConfigFile.get_config_file(LOGINDEFS) - if logindefs.exists(): - logindefs.replace_line_matching('^\s*PASS_MAX_DAYS', 'PASS_MAX_DAYS ' + str(max), 1) - uid_min = logindefs.get_match('^\s*UID_MIN\s+([0-9]+)', '@1') - if uid_min: - uid_min = int(uid_min) - shadow = ConfigFile.get_config_file(SHADOW) - if shadow.exists(): - _interactive and log(_('Setting password maximum aging for root and users with id greater than %d to %d and delay to %d days') % (uid_min, max, inactive)) - for line in shadow.get_lines(): - field = string.split(line, ':') - if len(field) < 2: - continue - name = field[0] - password = field[1] - if name in no_aging_list: - _interactive and log(_('User %s in password aging exception list') % (name,)) - continue - try: - entry = pwd.getpwnam(name) - except KeyError: - error(_('User %s in shadow but not in passwd file') % name) - continue - if (len(password) > 0 and password[0] != '!') and password != '*' and password != 'x' and (entry[2] >= uid_min or entry[2] == 0): - if field[4] == '': - current_max = 99999 - else: - current_max = int(field[4]) - if field[6] == '': - current_inactive = -1 - else: - current_inactive = int(field[6]) - new_max = max - new_inactive = inactive - # don't lower security when not changing security level - if same_level(): - if current_max < max and current_inactive < inactive: - continue - if current_max < max: - new_max = current_max - if current_inactive < inactive: - new_inactive = current_inactive - if new_max != current_max or current_inactive != new_inactive: - cmd = 'LC_ALL=C /usr/bin/chage -M %d -I %d -d %s \'%s\'' % (new_max, new_inactive, time.strftime('%Y-%m-%d'), entry[0]) - ret = commands.getstatusoutput(cmd) - log(_('changed maximum password aging for user \'%s\' with command %s') % (entry[0], cmd)) - -################################################################################ - -def allow_xauth_from_root(arg): - ''' Allow/forbid to export display when passing from the root account -to the other users. See pam_xauth(8) for more details.''' - export = ConfigFile.get_config_file(EXPORT) - - allow = export.exists() and export.get_match('^\*$') - - # don't lower security when not changing security level - if same_level(): - if not allow: - return - - if arg: - if not allow: - _interactive and log(_('Allowing export display from root')) - export.insert_at(0, '*') - else: - if allow: - _interactive and log(_('Forbidding export display from root')) - export.remove_line_matching('^\*$') - -################################################################################ - -def set_security_conf(var, value): - '''1 Set the variable \\fIvar\\fP to the value \\fIvalue\\fP in /var/lib/msec/security.conf. -The best way to override the default setting is to create /etc/security/msec/security.conf -with the value you want. These settings are used to configure the daily check run each night. - -The following variables are currentrly recognized by msec: - -CHECK_UNOWNED if set to yes, report unowned files. - -CHECK_SHADOW if set to yes, check empty password in /etc/shadow. - -CHECK_SUID_MD5 if set to yes, verify checksum of the suid/sgid files. - -CHECK_SECURITY if set to yes, run the daily security checks. - -CHECK_PASSWD if set to yes, check for empty passwords, for no password in /etc/shadow and for users with the 0 id other than root. - -SYSLOG_WARN if set to yes, report check result to syslog. - -CHECK_SUID_ROOT if set to yes, check additions/removals of suid root files. - -CHECK_PERMS if set to yes, check permissions of files in the users' home. - -CHKROOTKIT_CHECK if set to yes, run chkrootkit checks. - -CHECK_PROMISC if set to yes, check if the network devices are in promiscuous mode. - -RPM_CHECK if set to yes, run some checks against the rpm database. - -TTY_WARN if set to yes, reports check result to tty. - -CHECK_WRITABLE if set to yes, check files/directories writable by everybody. - -MAIL_WARN if set to yes, report check result by mail. - -MAIL_USER if set, send the mail report to this email address else send it to root. - -CHECK_OPEN_PORT if set to yes, check open ports. - -CHECK_SGID if set to yes, check additions/removals of sgid files. -''' - securityconf = ConfigFile.get_config_file(SECURITYCONF) - securityconf.set_shell_variable(var, value) - -# various - -def set_interactive(v): - "D" - - global _interactive - - _interactive = v - -# libmsec.py ends here - diff --git a/share/man.py b/share/man.py deleted file mode 100755 index 7859ed8..0000000 --- a/share/man.py +++ /dev/null @@ -1,67 +0,0 @@ -#!/usr/bin/python -#--------------------------------------------------------------- -# Project : Mandriva Linux -# Module : share -# File : man.py -# Version : $Id$ -# Author : Frederic Lepied -# Created On : Sat Jan 26 17:38:39 2002 -# Purpose : loads a python module and creates a man page from -# the doc strings of the functions. -#--------------------------------------------------------------- - -import sys -import imp -import inspect - -header = '''.ds q \N'34' -.TH mseclib 3 V0 msec "Mandriva Linux" -.SH NAME -mseclib -.SH SYNOPSIS -.nf -.B from mseclib import * -.B function1(yes) -.B function2(ignore) -.fi -.SH DESCRIPTION -.B mseclib -is a python library to access the function used by the msec program. This functions can be used -in /etc/security/msec/level.local to override the behaviour of the msec program or in standalone -scripts. The first argument of the functions takes a value of 1 or 0 or -1 (or yes/no/ignore) -except when specified otherwise. -''' - -footer = '''.RE -.SH "SEE ALSO" -msec(8) -.SH AUTHORS -Frederic Lepied <flepied@mandriva.com> -''' - -### strings used in the rewritting -function_str = ''' -.TP 4 -.B \\fI%s%s\\fP -%s -''' - -### code -modulename = sys.argv[1] - -module = __import__(modulename) - -sys.stdout.write(header) - -for f in inspect.getmembers(module, inspect.isfunction): - (args, varargs, varkw, locals) = inspect.getargspec(f[1]) - doc = f[1].__doc__ - if doc and len(doc) > 2: - doc = doc[2:] - argspec = inspect.formatargspec(args, varargs, varkw, locals) - s = function_str % (f[0], argspec, doc) - sys.stdout.write(s) - -sys.stdout.write(footer) - -# man.py ends here diff --git a/share/msec b/share/msec deleted file mode 100755 index f19cd9b..0000000 --- a/share/msec +++ /dev/null @@ -1,85 +0,0 @@ -#!/bin/sh -#--------------------------------------------------------------- -# Project : Mandriva Linux -# Module : share -# File : msec -# Version : $Id$ -# Author : Frederic Lepied -# Created On : Thu Dec 13 11:36:50 2001 -# Purpose : entry script to run hardness script or change -# the security level. -#--------------------------------------------------------------- - -if [ "`whoami`" != "root" ]; then - echo 'msec: sorry, you must be root !' - exit 1 -fi - -LCK=/var/run/msec.pid - -function cleanup() { - rm -f $LCK -} - -if [ -f $LCK ]; then - if [ -d /proc/`cat $LCK` ]; then - exit 0 - else - rm -f $LCK - fi -fi - -echo -n $$ > $LCK - -trap cleanup 0 - -MSEC=/usr/share/msec/msec.py -OPT="" - -for a in "$@"; do - if [ "$a" = '-o' ]; then - OPT="$OPT -o" - NEXT=1 - else - if [ "$NEXT" = 1 ]; then - OPT="$OPT $a" - else - last="$a" - fi - NEXT=0 - fi -done - -if [ -n "$last" ]; then - CHANGE=-c - case "$last" in - [0-5]) ;; - *) [ -x /usr/share/msec/$last.py ] && MSEC=/usr/share/msec/$last.py;; - esac -else - # no args so try to guess if a custom msec is needed - . /etc/sysconfig/msec - - case "$SECURE_LEVEL" in - [0-5]) ;; - *) MSEC=/usr/share/msec/$SECURE_LEVEL.py;; - esac -fi - -if [ ! -x "$MSEC" ]; then - echo "$MSEC not found or not executable. Aborting" 1>&2 - exit 1 -fi - -if $MSEC "$@"; then - . /etc/sysconfig/msec - - [ -z "$PERM_LEVEL" ] && PERM_LEVEL=$SECURE_LEVEL - - LOCAL= - [ -f /etc/security/msec/perm.local ] && LOCAL=/etc/security/msec/perm.local - - /usr/share/msec/Perms.py $CHANGE $OPT /usr/share/msec/perm.$PERM_LEVEL $LOCAL -fi - -# msec ends here diff --git a/share/msec.py b/share/msec.py deleted file mode 100755 index 553890c..0000000 --- a/share/msec.py +++ /dev/null @@ -1,290 +0,0 @@ -#!/usr/bin/python -O -#--------------------------------------------------------------- -# Project : Mandriva Linux -# Module : msec/share -# File : msec.py -# Version : $Id$ -# Author : Frederic Lepied -# Created On : Wed Dec 5 20:20:21 2001 -#--------------------------------------------------------------- - -from mseclib import * -from Log import * -from Log import _name -import Config -import ConfigFile - -import sys -import os -import string -import getopt -import gettext -import imp - -try: - cat = gettext.Catalog('msec') - _ = cat.gettext -except IOError: - _ = str - -# Eval a file -import mseclib -def import_only_mseclib(name, globals = None, locals = None, fromlist = None): - """ Import hook to allow only the mseclib module to be imported. """ - - if name == 'mseclib': - return mseclib - else: - raise ImportError, '%s cannot be imported' % name - -def eval_file(name): - """ Eval level.local file. Only allow mseclib to be imported for - backward compatibility. """ - - globals = {} - locals = {} - builtins = {} - - # Insert symbols from mseclib into globals - non_exported_names = ['FAKE', 'indirect', 'commit_changes', 'print_changes', 'get_translation'] - for attrib_name in dir(mseclib): - if attrib_name[0] != '_' and attrib_name not in non_exported_names: - globals[attrib_name] = getattr(mseclib, attrib_name) - - # Set import hook -- it needs to be in globals['__builtins'] so we make - # a copy of builtins to put there - builtins.update(__builtins__.__dict__) - builtins['__import__'] = import_only_mseclib - globals['__builtins__'] = builtins - - # Exec file - execfile(os.path.expanduser(name), globals, locals) - -# program -_name = 'msec' - -sys.argv[0] = os.path.basename(sys.argv[0]) - -try: - (opt, args) = getopt.getopt(sys.argv[1:], 'o:', - ['option']) -except getopt.error: - error(_('Invalid option. Use %s (-o var=<val>...) ([0-5])') % _name) - sys.exit(1) - - -for o in opt: - if o[0] == '-o' or o[0] == '--option': - pair = string.split(o[1], '=') - if len(pair) != 2: - error(_('Invalid option format %s %s: use -o var=<val>') % (o[0], o[1])) - sys.exit(1) - else: - Config.set_config(pair[0], pair[1]) - -interactive = sys.stdin.isatty() -set_interactive(interactive) - -# initlog must be done after processing the option because we can change -# the way to report log with options... -if interactive: - import syslog - - initlog('msec', syslog.LOG_LOCAL1) -else: - initlog('msec') - -if len(args) == 0: - level = get_secure_level() - if level == None: - error(_('Secure level not set. Use %s <secure level> to set it.') % _name) - sys.exit(1) -else: - level = args[0] - changing_level() - -try: - level = int(level) -except ValueError: - error(_('Invalid secure level %s. Use %s [0-5] to set it.') % (level, _name)) - sys.exit(1) - -if level < 0 or level > 5: - error(_('Invalid secure level %s. Use %s [0-5] to set it.') % (level, _name)) - sys.exit(1) - -interactive and log(_('### Program is starting ###')) - -set_secure_level(level) - -server=(level in range(3, 6)) - -# process options -server_level = Config.get_config('server_level') -if server_level: - set_server_level(server_level) - -create_server_link() - -# for all levels: min length = 2 * (level - 1) and for level 4,5 makes mandatory -# to have at least one upper case character and one digit. -if level > 1: - plength = (level - 1) * 2 -else: - plength = 0 - -password_length(plength, level / 4, level / 4) - -enable_ip_spoofing_protection(server) -enable_dns_spoofing_protection(server) - -# differences between level 5 and others -if level == 5: - set_root_umask('077') - set_shell_timeout(900) - authorize_services(NONE) - enable_pam_wheel_for_su(yes) - password_history(5) -else: - set_root_umask('022') - if level == 4: - set_shell_timeout(3600) - authorize_services(LOCAL) - else: - set_shell_timeout(0) - authorize_services(ALL) - enable_pam_wheel_for_su(no) - password_history(0) - -# differences between level 4,5 and others -if level >= 4: - set_user_umask('077') - set_shell_history_size(10) - allow_root_login(no) - enable_sulogin(yes) - allow_user_list(no) - enable_promisc_check(yes) - accept_icmp_echo(no) - accept_broadcasted_icmp_echo(no) - accept_bogus_error_responses(no) - allow_reboot(no) - enable_at_crontab(no) - if level == 4: - password_aging(60, 30) - else: - password_aging(30, 15) - allow_xauth_from_root(no) - set_win_parts_umask(None) -else: - set_user_umask('022') - set_shell_history_size(-1) - allow_root_login(yes) - enable_sulogin(no) - allow_user_list(yes) - enable_promisc_check(no) - accept_icmp_echo(yes) - accept_broadcasted_icmp_echo(yes) - accept_bogus_error_responses(yes) - allow_reboot(yes) - enable_at_crontab(yes) - password_aging(99999) - allow_xauth_from_root(yes) - -# special exception for ssh; if level == 3, set -# PermitRootLogin to without_password, otherwise set to no -# see https://qa.mandriva.com/show_bug.cgi?id=19726 -if level >= 3: - if level == 3: - allow_remote_root_login(without_password) - else: - allow_remote_root_login(no) -else: - allow_remote_root_login(yes) - -# differences between level 3,4,5 and others -if server: - allow_autologin(no) - enable_console_log(yes) - if level == 5: - allow_issues(NONE) - else: - allow_issues(LOCAL) - enable_log_strange_packets(yes) - enable_pam_root_from_wheel(no) -else: - allow_autologin(yes) - enable_console_log(no) - allow_issues(ALL) - enable_log_strange_packets(no) - enable_pam_root_from_wheel(yes) - set_win_parts_umask('0') - -# differences between level 0 and others -if level != 0: - enable_security_check(yes) - enable_password(yes) - if level < 3: - allow_x_connections(LOCAL) - allow_xserver_to_listen(yes) - else: - if level == 3: - allow_x_connections(NONE) - allow_xserver_to_listen(yes) - else: - allow_x_connections(NONE) - allow_xserver_to_listen(no) -else: - enable_security_check(no) - enable_password(no) - allow_x_connections(ALL, 1) - allow_xserver_to_listen(yes) - -# msec cron -enable_msec_cron(1) - -# 0 1 2 3 4 5 -FILE_CHECKS = {'CHECK_SECURITY' : ('no', 'yes', 'yes', 'yes', 'yes', 'yes', ), - 'CHECK_PERMS' : ('no', 'no', 'no', 'yes', 'yes', 'yes', ), - 'CHECK_SUID_ROOT' : ('no', 'no', 'yes', 'yes', 'yes', 'yes', ), - 'CHECK_SUID_MD5' : ('no', 'no', 'yes', 'yes', 'yes', 'yes', ), - 'CHECK_SGID' : ('no', 'no', 'yes', 'yes', 'yes', 'yes', ), - 'CHECK_WRITABLE' : ('no', 'no', 'yes', 'yes', 'yes', 'yes', ), - 'CHECK_UNOWNED' : ('no', 'no', 'no', 'no', 'yes', 'yes', ), - 'CHECK_PROMISC' : ('no', 'no', 'no', 'no', 'yes', 'yes', ), - 'CHECK_OPEN_PORT' : ('no', 'no', 'no', 'yes', 'yes', 'yes', ), - 'CHECK_PASSWD' : ('no', 'no', 'no', 'yes', 'yes', 'yes', ), - 'CHECK_SHADOW' : ('no', 'no', 'no', 'yes', 'yes', 'yes', ), - 'TTY_WARN' : ('no', 'no', 'no', 'no', 'yes', 'yes', ), - 'MAIL_WARN' : ('no', 'no', 'no', 'yes', 'yes', 'yes', ), - 'MAIL_EMPTY_CONTENT':('no', 'no', 'no', 'no', 'yes', 'yes', ), - 'SYSLOG_WARN' : ('no', 'no', 'yes', 'yes', 'yes', 'yes', ), - 'RPM_CHECK' : ('no', 'no', 'no', 'yes', 'yes', 'yes', ), - 'CHKROOTKIT_CHECK' : ('no', 'no', 'no', 'yes', 'yes', 'yes', ), - } - -for k in FILE_CHECKS.keys(): - set_security_conf(k, FILE_CHECKS[k][level]) - -if Config.get_config('nolocal', '0') == '0': - # load local customizations - CONFIG='/etc/security/msec/level.local' - if os.path.exists(CONFIG): - interactive and log(_('Reading local rules from %s') % CONFIG) - local_config(1) - try: - eval_file(CONFIG) - except: - log(_('Error loading %s: %s') % (CONFIG, str(sys.exc_value))) - local_config(0) - -if Config.get_config('print', '0') == '1': - print_changes() -else: - commit_changes() - -interactive and log(_('Writing config files and then taking needed actions')) -ConfigFile.write_files() - -closelog() - -# msec.py ends here diff --git a/share/shadow.py b/share/shadow.py deleted file mode 100755 index e49ebb4..0000000 --- a/share/shadow.py +++ /dev/null @@ -1,116 +0,0 @@ -#!/usr/bin/python -#--------------------------------------------------------------- -# Project : Mandriva Linux -# Module : msec/share -# File : shadow.py -# Version : $Id$ -# Author : Frederic Lepied -# Created On : Sat Jan 26 17:38:39 2002 -# Purpose : loads a python module and creates another one -# on stdout. All the functions of the module are shadowed according -# to their doc string: "D" direct mapping, "1" indirect call but -# name + first arg used as the key and all other cases indirect -# call with the name as the key. -#--------------------------------------------------------------- - -import sys -import imp -import inspect - -### strings used in the rewritting -direct_str = """ -%s=%s.%s - -""" - -indirect_str = """ -def %s(*args): - indirect(\"%s\", %s.%s, %d, args) - -""" - -header = """ - -NONE=0 -ALL=1 -LOCAL=2 - -yes=1 -no=0 -without_password=2 -ignore=-1 - -FAKE = {} - -_force = 0 - -def local_config(val): - global _force - _force = val - -def indirect(name, func, type, args): - if type == 1: - key = (name, args[0]) - else: - key = name - FAKE[key] = (func, args) - if _force: - force_val(name) - -def commit_changes(): - for f in FAKE.values(): - if len(f[1]) >= 1 and (f[1][0] != -1 or f[0].__name__ == 'set_shell_history_size'): - f[0](*f[1]) - elif len(f[1]) == 0: - f[0]() - -def print_changes(): - import sys - for f in FAKE.values(): - l = len(f[1]) - if l >= 1 and (f[1][0] != -1 or f[0].__name__ == 'set_shell_history_size'): - name = f[0].__name__ - try: - if f[0].one_arg: - l = 1 - except AttributeError: - pass - if l == 1: - print name, get_translation(f[0], f[1][0]) - else: - sys.stdout.write(name) - for a in f[1]: - sys.stdout.write(' ' + str(a)) - sys.stdout.write('\\n') - -def get_translation(func, value): - try: - return func.arg_trans[value] - except (KeyError, AttributeError): - return value - -""" - -### code -modulename = sys.argv[1] - -module = __import__(modulename) - -sys.stdout.write(header) - -sys.stdout.write("import %s\n\n" % modulename) - -for f in inspect.getmembers(module, inspect.isfunction): - (args, varargs, varkw, locals) = inspect.getargspec(f[1]) - if f[1].__doc__ and f[1].__doc__[0] == 'D': - #argspec = inspect.formatargspec(args, varargs, varkw, locals) - s = direct_str % (f[0], modulename, f[0]) - else: - if f[1].__doc__ and f[1].__doc__[0] == '1': - type = 1 - else: - type = 0 - s = indirect_str % (f[0], f[0], modulename, f[0], type) - sys.stdout.write(s) - -# shadow.py ends here |