remove lshell
There is security related issue with lshell, and it is not maintained now. So remove it from our system to avoid security issue. To remove lshell: 1. Package sudo-config is created for wrs.sudo configure file following the refactor process. 2. ldapusersetup in ldapscripts is modified to use bash only. lshell support is removed. ldapusersetup related patches are merged into 1 for easy maintenance. Test has been done: Build and deploy test is done, also unit tests for ldap are executed with pass, except lshell related test. Closes-Bug: 1795451 Change-Id: Ia5de1bc94d22eb6c9bea6d9a96e92564ad848b19 Signed-off-by: slin14 <shuicheng.lin@intel.com>
This commit is contained in:
parent
d7d8b3cf06
commit
6a6ea416e1
@ -1,25 +0,0 @@
|
||||
From 30a087a13a78b77537a969db2a30b531246b0bd7 Mon Sep 17 00:00:00 2001
|
||||
From: Don Penney <don.penney@windriver.com>
|
||||
Date: Mon, 26 Sep 2016 17:39:58 -0400
|
||||
Subject: [PATCH] Update package versioning for TIS format
|
||||
|
||||
---
|
||||
SPECS/lshell.spec | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/SPECS/lshell.spec b/SPECS/lshell.spec
|
||||
index 0fd4d17..e5f1317 100644
|
||||
--- a/SPECS/lshell.spec
|
||||
+++ b/SPECS/lshell.spec
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
Name: lshell
|
||||
Version: 0.9.16
|
||||
-Release: 6%{?dist}
|
||||
+Release: 5.el7%{?_tis_dist}.%{tis_patch_ver}
|
||||
Summary: A Python-based limited shell
|
||||
|
||||
License: GPLv3+
|
||||
--
|
||||
1.8.3.1
|
||||
|
@ -1,3 +0,0 @@
|
||||
spec-include-TiS-changes.patch
|
||||
spec-update-lshell-conf-allowed-list.patch
|
||||
0001-Update-package-versioning-for-TIS-format.patch
|
@ -1,87 +0,0 @@
|
||||
lshell.spec: to include Titanium Cloud changes
|
||||
|
||||
To include the Titanium Cloud specific changes from:
|
||||
|
||||
stx/stx-integ/base/lshell
|
||||
|
||||
diff -u b/SPECS/lshell.spec b/SPECS/lshell.spec
|
||||
--- b/SPECS/lshell.spec
|
||||
+++ b/SPECS/lshell.spec
|
||||
@@ -1,3 +1,5 @@
|
||||
+%define WRSROOT_P cBglipPpsKwBQ
|
||||
+
|
||||
Name: lshell
|
||||
Version: 0.9.16
|
||||
Release: 5%{?dist}
|
||||
@@ -6,6 +8,15 @@
|
||||
License: GPLv3+
|
||||
URL: https://github.com/ghantoos/lshell
|
||||
Source0: http://downloads.sourceforge.net/%{name}/%{name}-%{version}.tar.gz
|
||||
+Source1: cgcs_cli
|
||||
+Source2: lshell.conf
|
||||
+Source3: wrs.sudo
|
||||
+Source4: lshell_env_setup
|
||||
+Patch1: lshell_cgcs.patch
|
||||
+Patch2: lshell-source-support.patch
|
||||
+Patch3: lshell-prompt-change-support.patch
|
||||
+Patch4: lshell-newline-escape-character-support.patch
|
||||
+Patch5: lshell-shell-escape-check.patch
|
||||
BuildArch: noarch
|
||||
|
||||
BuildRequires: python2-devel
|
||||
@@ -20,6 +31,11 @@
|
||||
%setup -q
|
||||
#Fix permission
|
||||
chmod -x CHANGES
|
||||
+%patch1 -p1
|
||||
+%patch2 -p1
|
||||
+%patch3 -p1
|
||||
+%patch4 -p1
|
||||
+%patch5 -p1
|
||||
|
||||
%build
|
||||
%{__python2} setup.py build
|
||||
@@ -27,10 +43,25 @@
|
||||
%install
|
||||
%{__python2} setup.py install -O1 --skip-build --root=%{buildroot}
|
||||
# Doc files at the wrong place
|
||||
-rm %{buildroot}%{_defaultdocdir}/lshell/{CHANGES,COPYING,README}
|
||||
+rm -f %{buildroot}%{_defaultdocdir}/lshell/{CHANGES,COPYING,README}
|
||||
+mkdir -p ${RPM_BUILD_ROOT}/usr/local/bin
|
||||
+install -m 755 ${RPM_SOURCE_DIR}/cgcs_cli ${RPM_BUILD_ROOT}/usr/local/bin/cgcs_cli
|
||||
+install -m 755 ${RPM_SOURCE_DIR}/lshell_env_setup ${RPM_BUILD_ROOT}/usr/local/bin/lshell_env_setup
|
||||
+install -d ${RPM_BUILD_ROOT}/etc
|
||||
+install -m 644 ${RPM_SOURCE_DIR}/lshell.conf ${RPM_BUILD_ROOT}/etc/lshell.conf
|
||||
+install -d ${RPM_BUILD_ROOT}/etc/sudoers.d
|
||||
+cp ${RPM_SOURCE_DIR}/wrs.sudo wrs.sudo
|
||||
+echo 'Defaults passprompt="Password: "' >> wrs.sudo
|
||||
+install -m 440 wrs.sudo ${RPM_BUILD_ROOT}/etc/sudoers.d/wrs
|
||||
|
||||
%pre
|
||||
getent group lshell >/dev/null || groupadd -r lshell
|
||||
+getent group wrs >/dev/null || groupadd -r wrs
|
||||
+getent group wrs_protected >/dev/null || groupadd -f -g 345 wrs_protected
|
||||
+getent passwd wrsroot > /dev/null || \
|
||||
+useradd -m -g wrs -G root,wrs_protected \
|
||||
+ -d /home/wrsroot -p %{WRSROOT_P} \
|
||||
+ -s /bin/sh wrsroot 2> /dev/null || :
|
||||
|
||||
%post
|
||||
grep -q '^%{_bindir}/%{name}$' %{_sysconfdir}/shells || \
|
||||
@@ -42,13 +73,13 @@
|
||||
fi
|
||||
|
||||
%files
|
||||
-%doc CHANGES COPYING README
|
||||
-%{_mandir}/man*/*.*
|
||||
%{_bindir}/%{name}
|
||||
%config(noreplace) %{_sysconfdir}/%{name}.conf
|
||||
-%config(noreplace) %{_sysconfdir}/logrotate.d/%{name}
|
||||
+%config(noreplace) %{_sysconfdir}/sudoers.d/wrs
|
||||
%{python_sitelib}/lshell/
|
||||
%{python_sitelib}/%{name}*.egg-info
|
||||
+/usr/local/bin/cgcs_cli
|
||||
+/usr/local/bin/lshell_env_setup
|
||||
|
||||
%changelog
|
||||
* Wed Jun 17 2015 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.9.16-5
|
@ -1,15 +0,0 @@
|
||||
---
|
||||
lshell.spec | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/SPECS/lshell.spec
|
||||
+++ b/SPECS/lshell.spec
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
Name: lshell
|
||||
Version: 0.9.16
|
||||
-Release: 5%{?dist}
|
||||
+Release: 6%{?dist}
|
||||
Summary: A Python-based limited shell
|
||||
|
||||
License: GPLv3+
|
@ -1 +0,0 @@
|
||||
mirror:Source/lshell-0.9.16-5.el7.src.rpm
|
@ -1,2 +0,0 @@
|
||||
#!/bin/sh
|
||||
/usr/bin/lshell
|
@ -1,53 +0,0 @@
|
||||
---
|
||||
lshell/shellcmd.py | 26 +++++++++++++++++++++++++-
|
||||
1 file changed, 25 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/lshell/shellcmd.py
|
||||
+++ b/lshell/shellcmd.py
|
||||
@@ -74,6 +74,7 @@ class ShellCmd(cmd.Cmd, object):
|
||||
self.promptbase = getuser()
|
||||
|
||||
self.prompt = '%s:~$ ' % self.promptbase
|
||||
+ self.prompt2 = '> ' # PS2 prompt
|
||||
|
||||
self.intro = self.conf['intro']
|
||||
|
||||
@@ -670,6 +671,12 @@ class ShellCmd(cmd.Cmd, object):
|
||||
self.stdout.write("%s\n" % self.intro)
|
||||
if self.conf['login_script']:
|
||||
self.loginCmdParse(self.conf['login_script'])
|
||||
+
|
||||
+ # for long commands, a user may escape the new line
|
||||
+ # by giving a bash like '\' character at the end of
|
||||
+ # the line. cmdloop() needs to recognize that and
|
||||
+ # create an appended line before sending it to onecmd()
|
||||
+ partial_line = ""
|
||||
stop = None
|
||||
while not stop:
|
||||
if self.cmdqueue:
|
||||
@@ -691,7 +698,24 @@ class ShellCmd(cmd.Cmd, object):
|
||||
line = 'EOF'
|
||||
else:
|
||||
line = line[:-1] # chop \n
|
||||
- line = self.precmd(line)
|
||||
+
|
||||
+ if len(line) > 1 and line.startswith('\\'):
|
||||
+ # implying previous partial line
|
||||
+ line = line[:1].replace('\\', '', 1)
|
||||
+ if partial_line:
|
||||
+ line = partial_line + line
|
||||
+ if line.endswith('\\'):
|
||||
+ # continuation character. First partial line.
|
||||
+ # We shall expect the command to continue in
|
||||
+ # a new line. Change to bash like PS2 prompt to
|
||||
+ # indicate this continuation to the user
|
||||
+ partial_line = line.strip('\\')
|
||||
+ self.prompt = self.prompt2 # switching to PS2
|
||||
+ continue
|
||||
+ partial_line = ""
|
||||
+
|
||||
+ self.updateprompt(os.getcwd())
|
||||
+ line = self.precmd(line)
|
||||
stop = self.onecmd(line)
|
||||
stop = self.postcmd(stop, line)
|
||||
self.postloop()
|
@ -1,139 +0,0 @@
|
||||
---
|
||||
lshell/shellcmd.py | 77 ++++++++++++++++++++++++++++++++++++++++++++++++-----
|
||||
1 file changed, 71 insertions(+), 6 deletions(-)
|
||||
|
||||
--- a/lshell/shellcmd.py
|
||||
+++ b/lshell/shellcmd.py
|
||||
@@ -28,6 +28,7 @@ import readline
|
||||
import glob
|
||||
import subprocess
|
||||
|
||||
+from time import gmtime, strftime
|
||||
from utils import get_aliases
|
||||
|
||||
|
||||
@@ -50,6 +51,9 @@ class ShellCmd(cmd.Cmd, object):
|
||||
else:
|
||||
self.stderr = stderr
|
||||
|
||||
+ # create a devnull device
|
||||
+ self.devnull = open(os.devnull, 'w')
|
||||
+
|
||||
self.args = args
|
||||
self.conf = userconf
|
||||
self.log = self.conf['logpath']
|
||||
@@ -145,13 +149,63 @@ class ShellCmd(cmd.Cmd, object):
|
||||
self.g_cmd, self.g_arg, self.g_line = ['', '', '']
|
||||
return object.__getattribute__(self, attr)
|
||||
|
||||
+ def check_prompt(self, var, value):
|
||||
+ """ check if user is attempting to
|
||||
+ modify shell prompt and if so then
|
||||
+ update the prompt
|
||||
+ """
|
||||
+ if 'PS' in var:
|
||||
+ if 'PS1' in var:
|
||||
+ # update prompt
|
||||
+ self.promptbase = self.setprompt(
|
||||
+ {'prompt' : value.strip('\n').strip('\r')})
|
||||
+ self.updateprompt(os.getcwd())
|
||||
+ else:
|
||||
+ self.log.critical("*** forbidden %s prompt change requested. "
|
||||
+ "Only PS1 changes permissible" % var)
|
||||
+
|
||||
+
|
||||
def setprompt(self, conf):
|
||||
""" set prompt used by the shell
|
||||
"""
|
||||
if conf.has_key('prompt'):
|
||||
promptbase = conf['prompt']
|
||||
- promptbase = promptbase.replace('%u', getuser())
|
||||
- promptbase = promptbase.replace('%h', os.uname()[1].split('.')[0])
|
||||
+ # Recognize shell name control command
|
||||
+ promptbase = re.sub(r'\\s', 'lshell',
|
||||
+ promptbase)
|
||||
+ # Recognize username control command
|
||||
+ promptbase = re.sub(r'\\u|%u', getuser(),
|
||||
+ promptbase)
|
||||
+ # Recognize hostname control command
|
||||
+ promptbase = re.sub(r'\\h|%h', os.uname()[1].split('.')[0],
|
||||
+ promptbase)
|
||||
+ # Recognize full hostname control command
|
||||
+ promptbase = re.sub(r'\\H', os.uname()[1],
|
||||
+ promptbase)
|
||||
+ # Recognize time control commands
|
||||
+ promptbase = re.sub(r'\\t', strftime("%H:%M:%S", gmtime()),
|
||||
+ promptbase)
|
||||
+ promptbase = re.sub(r'\\T', strftime("%I:%M:%S", gmtime()),
|
||||
+ promptbase)
|
||||
+ promptbase = re.sub(r'\\A', strftime("%H:%M", gmtime()),
|
||||
+ promptbase)
|
||||
+ promptbase = re.sub(r'\\@', strftime("%I:%M:%S%p", gmtime()),
|
||||
+ promptbase)
|
||||
+ promptbase = re.sub(r'\\d', strftime("%a %b %d", gmtime()),
|
||||
+ promptbase)
|
||||
+ ########################################################
|
||||
+ # The following control commands are not supported: #
|
||||
+ # v - the shell version #
|
||||
+ # V - the shell release version #
|
||||
+ # w - Complete path of current working directory #
|
||||
+ # W - the basename of the current working directory #
|
||||
+ # ! - the history number of this command #
|
||||
+ # # - the command number of this command #
|
||||
+ # $? - status of the last command #
|
||||
+ # $() - any command executions #
|
||||
+ ########################################################
|
||||
+ promptbase = re.sub(r'\\v|\\V|\\w|\\W|\\!|\\#|\\\$\?|\\\$\(.*\)|\\\$', '',
|
||||
+ promptbase)
|
||||
else:
|
||||
promptbase = getuser()
|
||||
|
||||
@@ -199,7 +253,7 @@ class ShellCmd(cmd.Cmd, object):
|
||||
def export(self):
|
||||
""" export environment variables """
|
||||
# if command contains at least 1 space
|
||||
- if self.g_line.count(' '):
|
||||
+ if self.g_line.count(' '):
|
||||
env = self.g_line.split(" ", 1)[1]
|
||||
# if it conatins the equal sign, consider only the first one
|
||||
if env.count('='):
|
||||
@@ -216,6 +270,10 @@ class ShellCmd(cmd.Cmd, object):
|
||||
cin, cout = os.popen2('`which echo` %s' % value)
|
||||
value = cout.readlines()[0]
|
||||
|
||||
+ # check if new exported environment
|
||||
+ # is a prompt change command
|
||||
+ self.check_prompt(var, value)
|
||||
+
|
||||
os.environ.update({var: value.rstrip()})
|
||||
|
||||
def source(self):
|
||||
@@ -485,11 +543,14 @@ class ShellCmd(cmd.Cmd, object):
|
||||
p = subprocess.Popen( "`which echo` %s" % item,
|
||||
shell=True,
|
||||
stdin=subprocess.PIPE,
|
||||
- stdout=subprocess.PIPE )
|
||||
+ stdout=subprocess.PIPE,
|
||||
+ stderr = self.devnull )
|
||||
(cin, cout) = (p.stdin, p.stdout)
|
||||
except ImportError:
|
||||
- cin, cout = os.popen2('`which echo` %s' % item)
|
||||
- item = cout.readlines()[0].split(' ')[0].strip()
|
||||
+ cin, cout = os.popen2('`which echo` %s 2>/dev/null' % item)
|
||||
+ shellresponse = cout.readlines()
|
||||
+ if shellresponse:
|
||||
+ item = shellresponse[0].split(' ')[0].strip()
|
||||
item = os.path.expandvars(item)
|
||||
tomatch = os.path.realpath(item)
|
||||
if os.path.isdir(tomatch) and tomatch[-1] != '/': tomatch += '/'
|
||||
@@ -559,6 +620,10 @@ class ShellCmd(cmd.Cmd, object):
|
||||
if len(env) is not 2:
|
||||
continue
|
||||
newenv.update(dict([env]))
|
||||
+ # check if the new environment includes
|
||||
+ # any Shell prompt change commands
|
||||
+ self.check_prompt(env[0], env[1])
|
||||
+
|
||||
os.environ.update(newenv)
|
||||
|
||||
def loginCmdParse(self, script):
|
@ -1,121 +0,0 @@
|
||||
---
|
||||
lshell/shellcmd.py | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++--
|
||||
1 file changed, 77 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/lshell/shellcmd.py
|
||||
+++ b/lshell/shellcmd.py
|
||||
@@ -30,7 +30,7 @@ import subprocess
|
||||
|
||||
from time import gmtime, strftime
|
||||
from utils import get_aliases
|
||||
-
|
||||
+from distutils.spawn import find_executable
|
||||
|
||||
class ShellCmd(cmd.Cmd, object):
|
||||
""" Main lshell CLI class
|
||||
@@ -337,6 +337,44 @@ class ShellCmd(cmd.Cmd, object):
|
||||
# strip all spaces/tabs
|
||||
line = " ".join(line.split())
|
||||
|
||||
+ # Expand all variables
|
||||
+ line = os.path.expandvars(line)
|
||||
+
|
||||
+ # *** AWK HOOK *** #
|
||||
+ # Before we begin, check if user is trying
|
||||
+ # to pass an awk script to the awk interpreter
|
||||
+ # and disallow that option.
|
||||
+ #
|
||||
+ # Also disallow inline vars in awk since an attacker
|
||||
+ # may use that to scramble a forbidden cmd
|
||||
+ # such as the following shell escape:
|
||||
+ # (awk -v X=ba -v Y=ash 'BEGIN { system("/bin/"X Y) }'
|
||||
+ #
|
||||
+ # In an ideal world we should parse the awk script
|
||||
+ # and inline vars for forbidden paths and commands
|
||||
+ # but that will require some gnarly regexes (esp for
|
||||
+ # the inline vars). Deferring this as TODO
|
||||
+ if re.match(r'\s*awk.*-f\s*[\w/~]+', line):
|
||||
+ return self.warn_count('awk script option', oline, strict, ssh)
|
||||
+ if re.match(r'\s*awk.*-v\s*\w+=', line):
|
||||
+ return self.warn_count('awk inline variable option', oline, strict, ssh)
|
||||
+
|
||||
+
|
||||
+ # process all quoted text seperately
|
||||
+ # This logic is kept crudely simple on purpose.
|
||||
+ # At most we might match the same stanza twice
|
||||
+ # (for e.g. "'a'", 'a') but the converse would
|
||||
+ # require detecting single quotation stanzas
|
||||
+ # nested within double quotes and vice versa
|
||||
+ relist = re.findall(r'[^=]\"(.+)\"',line)
|
||||
+ relist2 = re.findall(r'[^=]\'(.+)\'',line)
|
||||
+ relist = relist + relist2
|
||||
+ for item in relist:
|
||||
+ if self.check_secure(item, strict = strict):
|
||||
+ return 1
|
||||
+ if self.check_path(item, strict = strict):
|
||||
+ return 1
|
||||
+
|
||||
# ignore quoted text
|
||||
line = re.sub(r'\"(.+?)\"', '', line)
|
||||
line = re.sub(r'\'(.+?)\'', '', line)
|
||||
@@ -438,7 +476,8 @@ class ShellCmd(cmd.Cmd, object):
|
||||
new_cmd_line = 'export ' + oline
|
||||
self.g_line = new_cmd_line
|
||||
self.check_secure(new_cmd_line, strict = strict)
|
||||
- else:
|
||||
+ # filter out macros, text or constructs that got picked up as commands
|
||||
+ elif command.islower() and find_executable(command):
|
||||
return self.warn_count('command', oline, strict, ssh, command)
|
||||
return 0
|
||||
|
||||
@@ -499,6 +538,7 @@ class ShellCmd(cmd.Cmd, object):
|
||||
%(self.conf['warning_counter']))
|
||||
self.stderr.write('This incident has been reported.\n')
|
||||
|
||||
+
|
||||
def check_path(self, line, completion=None, ssh=None, strict=None):
|
||||
""" Check if a path is entered in the line. If so, it checks if user \
|
||||
are allowed to see this path. If user is not allowed, it calls \
|
||||
@@ -594,7 +634,41 @@ class ShellCmd(cmd.Cmd, object):
|
||||
detect the new environment and then use that to update the \
|
||||
environ of the lshell process.
|
||||
"""
|
||||
- pipe = subprocess.Popen("%s; env -0" % script,
|
||||
+ try:
|
||||
+ script_path = os.path.expanduser(script.\
|
||||
+ strip("source").split()[0])
|
||||
+ script_path = os.path.expandvars(script_path)
|
||||
+ with open (script_path) as fd:
|
||||
+ content = fd.readlines()
|
||||
+ content = [line.strip('\n') for line in content]
|
||||
+
|
||||
+ # Although rare in a normal cases, an attacker
|
||||
+ # may attempt to bypass line validation by
|
||||
+ # scrambling commands via line continuations
|
||||
+ partial_line = ""
|
||||
+ for i,line in enumerate(content):
|
||||
+ if line.startswith('#'):
|
||||
+ continue
|
||||
+ if len(line) > 1 and line.startswith('\\'):
|
||||
+ # implying previous partial line
|
||||
+ content[i] = line[:1].replace('\\', '', 1)
|
||||
+ if partial_line:
|
||||
+ content[i] = partial_line + line
|
||||
+ if line.endswith('\\'):
|
||||
+ # continuation character. First partial line.
|
||||
+ # We shall expect the command to continue in
|
||||
+ # a new line.
|
||||
+ partial_line = content[i].strip('\\')
|
||||
+ continue
|
||||
+ partial_line = ""
|
||||
+ if self.check_secure(content[i]):
|
||||
+ return
|
||||
+ if self.check_path(content[i]):
|
||||
+ return
|
||||
+ except:
|
||||
+ pass
|
||||
+
|
||||
+ pipe = subprocess.Popen("%s; env -0" % script,
|
||||
bufsize=1,
|
||||
stdout=subprocess.PIPE,
|
||||
shell=True)
|
@ -1,106 +0,0 @@
|
||||
---
|
||||
lshell/shellcmd.py | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
|
||||
1 file changed, 64 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/lshell/shellcmd.py
|
||||
+++ b/lshell/shellcmd.py
|
||||
@@ -26,6 +26,7 @@ import re
|
||||
import signal
|
||||
import readline
|
||||
import glob
|
||||
+import subprocess
|
||||
|
||||
from utils import get_aliases
|
||||
|
||||
@@ -128,6 +129,9 @@ class ShellCmd(cmd.Cmd, object):
|
||||
# builtin export function
|
||||
elif self.g_cmd == 'export':
|
||||
self.export()
|
||||
+ # builtin source function
|
||||
+ elif self.g_cmd == 'source':
|
||||
+ self.source()
|
||||
# case 'cd' is in an alias e.g. {'toto':'cd /var/tmp'}
|
||||
elif self.g_line[0:2] == 'cd':
|
||||
self.g_cmd = self.g_line.split()[0]
|
||||
@@ -214,6 +218,14 @@ class ShellCmd(cmd.Cmd, object):
|
||||
|
||||
os.environ.update({var: value.rstrip()})
|
||||
|
||||
+ def source(self):
|
||||
+ """ implementation of the "source" command
|
||||
+ """
|
||||
+ # ensure if command contains at least 1 space
|
||||
+ if self.g_line.count(' '):
|
||||
+ source_script = self.g_line
|
||||
+ self.sourceShell(source_script)
|
||||
+
|
||||
def cd(self):
|
||||
""" implementation of the "cd" command
|
||||
"""
|
||||
@@ -515,6 +527,57 @@ class ShellCmd(cmd.Cmd, object):
|
||||
else:
|
||||
self.prompt = '%s:%s$ ' % (self.promptbase, path)
|
||||
|
||||
+ def sourceShell(self, script):
|
||||
+ """Source the shell script and call env when done in order to \
|
||||
+ detect the new environment and then use that to update the \
|
||||
+ environ of the lshell process.
|
||||
+ """
|
||||
+ pipe = subprocess.Popen("%s; env -0" % script,
|
||||
+ bufsize=1,
|
||||
+ stdout=subprocess.PIPE,
|
||||
+ shell=True)
|
||||
+
|
||||
+ iterator = iter(pipe.stdout.readline, b'')
|
||||
+ outputlist = list(iterator)
|
||||
+ output = ''
|
||||
+ for i, line in enumerate(outputlist):
|
||||
+ if i == (len(outputlist) -1):
|
||||
+ output = line
|
||||
+ else:
|
||||
+ sys.stdout.write(line)
|
||||
+
|
||||
+ # output may pick up some echos at the end of script and merge
|
||||
+ # with the first line in env. Test for this and echo those to stdout
|
||||
+ envList = output.split('\0')
|
||||
+ firstenv = re.findall('^\S+=\S+$', envList[0], re.MULTILINE)
|
||||
+ if firstenv:
|
||||
+ print envList[0].strip(firstenv[0])
|
||||
+ envList[0] = firstenv[0]
|
||||
+ newenv = {}
|
||||
+ for line in envList:
|
||||
+ env = line.split("=", 1)
|
||||
+ if len(env) is not 2:
|
||||
+ continue
|
||||
+ newenv.update(dict([env]))
|
||||
+ os.environ.update(newenv)
|
||||
+
|
||||
+ def loginCmdParse(self, script):
|
||||
+ """Parse the login command specified in login_script. \
|
||||
+ If login_script or a sub script sources a bash config \
|
||||
+ then call shell_source()
|
||||
+ """
|
||||
+ # if multiple commands are chained together, execute
|
||||
+ # them individually. We will not support conditional
|
||||
+ # chaining (&& or ||) since that would required the
|
||||
+ # additional complexity of checking the retcode of
|
||||
+ # the previous command
|
||||
+ cmds = script.split(";")
|
||||
+ for cmd in cmds:
|
||||
+ if "source" in cmd:
|
||||
+ self.sourceShell(cmd)
|
||||
+ else:
|
||||
+ os.system(cmd)
|
||||
+
|
||||
def cmdloop(self, intro=None):
|
||||
"""Repeatedly issue a prompt, accept input, parse an initial prefix \
|
||||
off the received input, and dispatch to action methods, passing them \
|
||||
@@ -541,7 +604,7 @@ class ShellCmd(cmd.Cmd, object):
|
||||
if self.intro and isinstance(self.intro, str):
|
||||
self.stdout.write("%s\n" % self.intro)
|
||||
if self.conf['login_script']:
|
||||
- os.system(self.conf['login_script'])
|
||||
+ self.loginCmdParse(self.conf['login_script'])
|
||||
stop = None
|
||||
while not stop:
|
||||
if self.cmdqueue:
|
@ -1,94 +0,0 @@
|
||||
# lshell.py configuration file
|
||||
#
|
||||
# $Id: lshell.conf,v 1.27 2010-10-18 19:05:17 ghantoos Exp $
|
||||
|
||||
[global]
|
||||
## log directory (default /var/log/lshell/ )
|
||||
logpath : /var/log/lshell/
|
||||
## set log level to 0, 1, 2, 3 or 4 (0: no logs, 1: least verbose,
|
||||
## 4: log all commands)
|
||||
loglevel : 2
|
||||
## configure log file name (default is %u i.e. username.log)
|
||||
#logfilename : %y%m%d-%u
|
||||
#logfilename : syslog
|
||||
|
||||
## in case you are using syslog, you can choose your logname
|
||||
#syslogname : myapp
|
||||
|
||||
[default]
|
||||
## a list of the allowed commands or 'all' to allow all commands in user's PATH
|
||||
allowed : ['source','vim','awk','cut','grep','cat','env','export', 'read', 'pwd','ls','echo','cd','ll','less','cp','scp','sftp','mv','rm','nova','system','neutron','cinder','glance','ceilometer','heat','keystone','passwd','openstack']
|
||||
|
||||
## a list of forbidden character or commands -- deny vim, as it allows to escape lshell
|
||||
#forbidden : [';', '&', '|','`','>','<', '$(', '${']
|
||||
forbidden : [';', '&', '>','<', '$(']
|
||||
|
||||
## a list of allowed command to use with sudo(8)
|
||||
#sudo_commands : ['ls', 'more']
|
||||
|
||||
## number of warnings when user enters a forbidden value before getting
|
||||
## exited from lshell, set to -1 to disable.
|
||||
warning_counter : 2
|
||||
|
||||
## command aliases list (similar to bash’s alias directive)
|
||||
aliases : {'ll':'ls -l', 'vim':'rvim'}
|
||||
|
||||
## introduction text to print (when entering lshell)
|
||||
#intro : "== My personal intro ==\nWelcome to lshell\nType '?' or 'help' to get the list of allowed commands"
|
||||
|
||||
## configure your promt using %u or %h (default: username)
|
||||
prompt : "%u@%h"
|
||||
|
||||
## set sort prompt current directory update (default: 0)
|
||||
#prompt_short : 0
|
||||
|
||||
## a value in seconds for the session timer
|
||||
timer : 900
|
||||
|
||||
## list of path to restrict the user "geographicaly"
|
||||
#path : ['/home/bla/','/etc']
|
||||
|
||||
## set the home folder of your user. If not specified the home_path is set to
|
||||
## the $HOME environment variable
|
||||
#home_path : '/home/bla/'
|
||||
|
||||
## update the environment variable $PATH of the user
|
||||
#env_path : ':/usr/local/bin:/usr/sbin'
|
||||
|
||||
## a list of path; all executable files inside these path will be allowed
|
||||
#allowed_cmd_path: ['/home/bla/bin','/home/bla/stuff/libexec']
|
||||
|
||||
## add environment variables
|
||||
#env_vars : {'foo':1, 'bar':'helloworld'}
|
||||
env_vars : {'OPENRC_TEMPLATE':'/etc/nova/ldap_openrc_template'}
|
||||
## allow or forbid the use of scp (set to 1 or 0)
|
||||
#scp : 1
|
||||
|
||||
## forbid scp upload
|
||||
#scp_upload : 0
|
||||
|
||||
## forbid scp download
|
||||
#scp_download : 0
|
||||
|
||||
## allow of forbid the use of sftp (set to 1 or 0)
|
||||
#sftp : 1
|
||||
|
||||
## list of command allowed to execute over ssh (e.g. rsync, rdiff-backup, etc.)
|
||||
#overssh : ['ls', 'rsync']
|
||||
|
||||
## logging strictness. If set to 1, any unknown command is considered as
|
||||
## forbidden, and user's warning counter is decreased. If set to 0, command is
|
||||
## considered as unknown, and user is only warned (i.e. *** unknown synthax)
|
||||
strict : 0
|
||||
|
||||
## force files sent through scp to a specific directory
|
||||
#scpforce : '/home/bla/uploads/'
|
||||
|
||||
## history file maximum size
|
||||
history_size : 100
|
||||
|
||||
## set history file name (default is /home/%u/.lhistory)
|
||||
#history_file : "/home/%u/.lshell_history"
|
||||
|
||||
## define the script to run at user login
|
||||
login_script : "source /usr/local/bin/lshell_env_setup --mute; install -m 0500 /usr/local/bin/lshell_env_setup ~/"
|
@ -1,54 +0,0 @@
|
||||
Index: lshell-0.9.16/setup.py
|
||||
===================================================================
|
||||
--- lshell-0.9.16.orig/setup.py
|
||||
+++ lshell-0.9.16/setup.py
|
||||
@@ -40,10 +40,7 @@ choose a list of allowed commands for ev
|
||||
scripts = ['bin/lshell'],
|
||||
package_dir = {'lshell':'lshell'},
|
||||
packages = ['lshell'],
|
||||
- data_files = [('/etc', ['etc/lshell.conf']),
|
||||
- ('/etc/logrotate.d', ['etc/logrotate.d/lshell']),
|
||||
- ('share/doc/lshell',['README', 'COPYING', 'CHANGES']),
|
||||
- ('share/man/man1/', ['man/lshell.1']) ],
|
||||
+ data_files = [],
|
||||
classifiers=[
|
||||
'Development Status :: 5 - Production/Stable',
|
||||
'Environment :: Console'
|
||||
Index: lshell-0.9.16/lshell/shellcmd.py
|
||||
===================================================================
|
||||
--- lshell-0.9.16.orig/lshell/shellcmd.py
|
||||
+++ lshell-0.9.16/lshell/shellcmd.py
|
||||
@@ -199,7 +199,7 @@ class ShellCmd(cmd.Cmd, object):
|
||||
env = self.g_line.split(" ", 1)[1]
|
||||
# if it conatins the equal sign, consider only the first one
|
||||
if env.count('='):
|
||||
- var, value = env.split(' ')[0].split('=')[0:2]
|
||||
+ var, value = env.split('=', 1)
|
||||
# expand values, if variable is surcharged by other variables
|
||||
try:
|
||||
import subprocess
|
||||
@@ -212,7 +212,7 @@ class ShellCmd(cmd.Cmd, object):
|
||||
cin, cout = os.popen2('`which echo` %s' % value)
|
||||
value = cout.readlines()[0]
|
||||
|
||||
- os.environ.update({var: value})
|
||||
+ os.environ.update({var: value.rstrip()})
|
||||
|
||||
def cd(self):
|
||||
""" implementation of the "cd" command
|
||||
@@ -361,7 +361,14 @@ class ShellCmd(cmd.Cmd, object):
|
||||
|
||||
# for all other commands check in allowed list
|
||||
if command not in self.conf['allowed'] and command:
|
||||
- return self.warn_count('command', oline, strict, ssh, command)
|
||||
+ export_pattern = re.compile('^[a-zA-Z0-9\-\_]*=')
|
||||
+ if export_pattern.match(oline):
|
||||
+ self.g_cmd = 'export'
|
||||
+ new_cmd_line = 'export ' + oline
|
||||
+ self.g_line = new_cmd_line
|
||||
+ self.check_secure(new_cmd_line, strict = strict)
|
||||
+ else:
|
||||
+ return self.warn_count('command', oline, strict, ssh, command)
|
||||
return 0
|
||||
|
||||
def warn_count(self, messagetype, line=None, strict=None, ssh=None, command=None):
|
@ -1,100 +0,0 @@
|
||||
#!/bin/bash
|
||||
MAX_OPENRC_LEN=100
|
||||
read -p "Pre-store Keystone user credentials for this session? (y/N): " confirm
|
||||
confirm=${confirm,,}
|
||||
|
||||
if [ "$confirm" == "y" ] || [ "$confirm" = "yes" ]; then
|
||||
if [ -z "$OPENRC_TEMPLATE" ] || [ ! -f `echo $OPENRC_TEMPLATE` ]; then
|
||||
read -p "env[OPENRC_TEMPLATE] not set.
|
||||
Hints will not be available for certain options. Continue anyways? (Y/n): " confirm
|
||||
confirm=${confirm,,}
|
||||
([ "$confirm" == "n" ] || [ "$confirm" == "no" ]) && exit 0
|
||||
else
|
||||
# Check if we are to run Muted
|
||||
[ "$1" = "--mute" ] && MUTE=1
|
||||
|
||||
# Load default values for System URL, Region and Keystone URL
|
||||
defEnv=( $(cat $OPENRC_TEMPLATE) )
|
||||
defEnvLen=${#defEnv[@]}
|
||||
[ "$defEnvLen" -gt "$MAX_OPENRC_LEN" ] && \
|
||||
defEnvLen="$MAX_OPENRC_LEN"
|
||||
for (( i=0; i<$defEnvLen; i++));
|
||||
do
|
||||
if [[ ${defEnv[$i]} =~ OS_AUTH_URL=(.*)$ ]]; then
|
||||
def_os_auth_url=${BASH_REMATCH[1]}
|
||||
elif [[ ${defEnv[$i]} =~ OS_REGION_NAME=(.*)$ ]]; then
|
||||
def_os_region_name=${BASH_REMATCH[1]}
|
||||
elif [[ ${defEnv[$i]} =~ OS_PROJECT_NAME=(.*)$ ]]; then
|
||||
def_os_project_name=${BASH_REMATCH[1]}
|
||||
elif [[ ${defEnv[$i]} =~ OS_USER_DOMAIN_NAME=(.*)$ ]]; then
|
||||
def_os_user_domain_name=${BASH_REMATCH[1]}
|
||||
elif [[ ${defEnv[$i]} =~ OS_PROJECT_DOMAIN_NAME=(.*)$ ]]; then
|
||||
def_os_project_domain_name=${BASH_REMATCH[1]}
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
read -p "Enter Keystone username [$USER]: " os_user
|
||||
[ -z "$os_user" ] && os_user="$USER"
|
||||
|
||||
read -p "Enter Keystone user domain name: " os_user_domain_name
|
||||
[ -z "$os_user_domain_name" ] && os_user_domain_name="$def_os_user_domain_name"
|
||||
|
||||
read -p "Enter Project name: " os_project_name
|
||||
[ -z "$os_project_name" ] && os_project_name="$def_os_project_name"
|
||||
|
||||
read -p "Enter Project domain name: " os_project_domain_name
|
||||
[ -z "$os_project_domain_name" ] && os_project_domain_name="$def_os_project_domain_name"
|
||||
|
||||
read -s -p "Enter Keystone password: " os_pass
|
||||
[ -z "$os_pass" ] && \
|
||||
echo -n "Invalid password entry. Aborting!" && exit 1
|
||||
|
||||
# if we are not in mute mode then ask for these
|
||||
# from user as input
|
||||
if [ -z "$MUTE" ]; then
|
||||
if [ -z "$def_os_region_name" ]; then
|
||||
read -p "\n\nEnter Keystone Region Name: " os_region
|
||||
else
|
||||
read -p "Enter Keystone Region Name [$def_os_region_name]: " os_region
|
||||
[ -z "$os_region" ] && os_region="$def_os_region_name"
|
||||
fi
|
||||
|
||||
if [ -z "$def_os_auth_url" ]; then
|
||||
read -p "Enter Keystone Authentication URL: " os_auth_url
|
||||
else
|
||||
read -p "Enter Keystone Authentication URL [$def_os_auth_url]: " os_auth_url
|
||||
[ -z "$os_auth_url" ] && os_auth_url="$def_os_auth_url"
|
||||
fi
|
||||
else
|
||||
# In MUTE mode
|
||||
os_region="$def_os_region_name"
|
||||
echo ""; echo ""
|
||||
echo "Using default Openstack Region Name: $os_region"
|
||||
os_auth_url="$def_os_auth_url"
|
||||
echo "Using default Openstack Authentication URL: $os_auth_url"
|
||||
echo "To set these to non-default, run \"source ~/$(basename $BASH_SOURCE)\" in your shell"
|
||||
fi
|
||||
|
||||
|
||||
# set user environment which will be valid for
|
||||
# the duration of this session
|
||||
# Since lshell is running for internal clients
|
||||
# move OS ENDPOINT TYPE to internalURL
|
||||
export OS_ENDPOINT_TYPE="internalURL"
|
||||
export CINDER_ENDPOINT_TYPE="internalURL"
|
||||
export OS_INTERFACE="internal"
|
||||
export OS_USERNAME="$os_user"
|
||||
export OS_PASSWORD="$os_pass"
|
||||
export OS_PROJECT_NAME="$os_project_name"
|
||||
export OS_USER_DOMAIN_NAME="$os_user_domain_name"
|
||||
export OS_PROJECT_DOMAIN_NAME="$os_project_domain_name"
|
||||
export OS_AUTH_URL="$os_auth_url"
|
||||
export OS_IDENTITY_API_VERSION=3
|
||||
export OS_REGION_NAME="$os_region"
|
||||
# modify PS1 prompt
|
||||
newprompt="[\u@\h \W($os_user)]\$ "
|
||||
export PS1="$newprompt"
|
||||
echo ""
|
||||
echo "Keystone credentials preloaded!"
|
||||
fi
|
@ -169,9 +169,6 @@ initscripts
|
||||
# setup
|
||||
setup
|
||||
|
||||
# lshell
|
||||
lshell
|
||||
|
||||
# nss-pam-ldapd
|
||||
nss-pam-ldapd
|
||||
|
||||
@ -232,6 +229,9 @@ novnc
|
||||
# sudo
|
||||
sudo
|
||||
|
||||
# config files
|
||||
sudo-config
|
||||
|
||||
# net-snmp
|
||||
net-snmp-utils
|
||||
net-snmp-libs
|
||||
|
@ -2,7 +2,6 @@ tools/vm-topology
|
||||
base/initscripts
|
||||
base/util-linux
|
||||
base/setup
|
||||
base/lshell
|
||||
utilities/namespace-utils
|
||||
ldap/nss-pam-ldapd
|
||||
base/centos-release
|
||||
@ -103,6 +102,7 @@ logging/logmgmt
|
||||
filesystem/filesystem-scripts
|
||||
utilities/branding
|
||||
config-files/io-scheduler
|
||||
config-files/sudo-config
|
||||
tools/collector
|
||||
grub/grubby
|
||||
utilities/platform-util
|
||||
|
@ -1,2 +1,2 @@
|
||||
COPY_LIST="files/*"
|
||||
TIS_PATCH_VER=4
|
||||
TIS_PATCH_VER=0
|
32
config-files/sudo-config/centos/sudo-config.spec
Normal file
32
config-files/sudo-config/centos/sudo-config.spec
Normal file
@ -0,0 +1,32 @@
|
||||
Summary: StarlingX Sudo Configuration File
|
||||
Name: sudo-config
|
||||
Version: 1.0
|
||||
Release: %{tis_patch_ver}%{?_tis_dist}
|
||||
License: Apache-2.0
|
||||
Group: base
|
||||
Packager: StarlingX
|
||||
URL: unknown
|
||||
|
||||
Source0: wrs.sudo
|
||||
Source1: LICENSE
|
||||
|
||||
%define WRSROOT_P cBglipPpsKwBQ
|
||||
|
||||
%description
|
||||
StarlingX sudo configuration file
|
||||
|
||||
%install
|
||||
install -d %{buildroot}/%{_sysconfdir}/sudoers.d
|
||||
install -m 440 %{SOURCE0} %{buildroot}/%{_sysconfdir}/sudoers.d/wrs
|
||||
|
||||
%pre
|
||||
getent group wrs >/dev/null || groupadd -r wrs
|
||||
getent group wrs_protected >/dev/null || groupadd -f -g 345 wrs_protected
|
||||
getent passwd wrsroot > /dev/null || \
|
||||
useradd -m -g wrs -G root,wrs_protected \
|
||||
-d /home/wrsroot -p %{WRSROOT_P} \
|
||||
-s /bin/sh wrsroot 2> /dev/null || :
|
||||
|
||||
%files
|
||||
%license ../SOURCES/LICENSE
|
||||
%config(noreplace) %{_sysconfdir}/sudoers.d/wrs
|
202
config-files/sudo-config/files/LICENSE
Normal file
202
config-files/sudo-config/files/LICENSE
Normal file
@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
@ -9,3 +9,4 @@ wrsroot ALL=(root) NOPASSWD: /usr/bin/config_management
|
||||
wrsroot ALL=(root) NOPASSWD: /usr/local/sbin/collect
|
||||
|
||||
Defaults lecture=never, secure_path=/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin
|
||||
Defaults passprompt="Password: "
|
@ -19,9 +19,7 @@ Patch0: sudo-support.patch
|
||||
Patch1: sudo-delete-support.patch
|
||||
Patch2: log_timestamp.patch
|
||||
Patch3: ldap-user-setup-support.patch
|
||||
Patch4: ldap-user-setup-support-input-validation.patch
|
||||
Patch5: ldap-user-setup-noninteractive-mode-fix.patch
|
||||
Patch6: allow-anonymous-bind-for-ldap-search.patch
|
||||
Patch4: allow-anonymous-bind-for-ldap-search.patch
|
||||
|
||||
%define debug_package %{nil}
|
||||
|
||||
@ -31,7 +29,6 @@ Patch6: allow-anonymous-bind-for-ldap-search.patch
|
||||
%description
|
||||
Shell scripts that allow to manage POSIX accounts (users, groups, machines) in an LDAP directory.
|
||||
|
||||
|
||||
%prep
|
||||
%setup -q
|
||||
%patch0 -p1
|
||||
@ -39,20 +36,16 @@ Shell scripts that allow to manage POSIX accounts (users, groups, machines) in a
|
||||
%patch2 -p1
|
||||
%patch3 -p1
|
||||
%patch4 -p1
|
||||
%patch5 -p1
|
||||
%patch6 -p1
|
||||
|
||||
|
||||
%build
|
||||
|
||||
|
||||
%install
|
||||
make install DESTDIR=%{buildroot}
|
||||
|
||||
rm -Rf %{buildroot}/usr/local/man
|
||||
rm -f %{buildroot}/usr/local/sbin/*machine*
|
||||
rm -f %{buildroot}/usr/local/etc/ldapscripts/ldapaddmachine.template.sample
|
||||
install -d ldroot}}/usr/local/etc/
|
||||
install -d %{buildroot}/usr/local/etc/
|
||||
install -m 644 %{SOURCE1} %{buildroot}/usr/local/etc/ldapscripts/ldapscripts.conf
|
||||
install -m 644 %{SOURCE2} %{buildroot}/usr/local/etc/ldapscripts/ldapadduser.template.cgcs
|
||||
install -m 644 %{SOURCE3} %{buildroot}/usr/local/etc/ldapscripts/ldapaddgroup.template.cgcs
|
||||
|
@ -1,15 +0,0 @@
|
||||
---
|
||||
sbin/ldapusersetup | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/sbin/ldapusersetup
|
||||
+++ b/sbin/ldapusersetup
|
||||
@@ -105,7 +105,7 @@ LdapAddLoginShell () {
|
||||
;;
|
||||
esac
|
||||
else
|
||||
- shellopn=${$2,,}
|
||||
+ shellopn=${2,,}
|
||||
case $shellopn in
|
||||
"bash") _SHELL="/bin/sh";;
|
||||
"lshell") _SHELL="$_DEFAULTLSHELL";;
|
@ -1,87 +0,0 @@
|
||||
---
|
||||
sbin/ldapusersetup | 45 ++++++++++++++++++++++++++++++++++-----------
|
||||
1 file changed, 34 insertions(+), 11 deletions(-)
|
||||
|
||||
--- a/sbin/ldapusersetup
|
||||
+++ b/sbin/ldapusersetup
|
||||
@@ -44,6 +44,29 @@ _SHELL=""
|
||||
|
||||
### Helper functions ###
|
||||
|
||||
+# Gets input from user and validates it.
|
||||
+# Will only return if input meets validation
|
||||
+# criteria otherwise will just sit there.
|
||||
+#
|
||||
+# Input : input string ($1), valid output options ($2)
|
||||
+# Output: the validated input
|
||||
+# Note : the validation list must be an array
|
||||
+LdapUserInput () {
|
||||
+declare -a optionAry=("${!2}")
|
||||
+while true; do
|
||||
+ read -p "$1" _output
|
||||
+ # convert to lower case
|
||||
+ _output2=${_output,,}
|
||||
+ # check if output is a valid option
|
||||
+ if [[ "${optionAry[@]}" =~ "$_output2" ]]; then
|
||||
+ break
|
||||
+ else
|
||||
+ echo "Invalid input \"$_output\". Allowed options: ${optionAry[@]}" >&2
|
||||
+ fi
|
||||
+done
|
||||
+ echo "$_output2"
|
||||
+}
|
||||
+
|
||||
# Delete an ldap user if it exists
|
||||
# and exit with error
|
||||
# Input : username ($1), exit msg ($2)
|
||||
@@ -67,10 +90,12 @@ LdapAddUser() {
|
||||
LdapAddLoginShell () {
|
||||
if [ -z "$2" ]; then
|
||||
# Ask the user for the login shell
|
||||
- echo "Select Login Shell option # [2]:
|
||||
+ shellInput="Select Login Shell option # [2]:
|
||||
1) Bash
|
||||
-2) Lshell"
|
||||
- read opn
|
||||
+2) Lshell
|
||||
+"
|
||||
+ options=( 1, 2 )
|
||||
+ opn=`LdapUserInput "$shellInput" options[@]`
|
||||
case $opn in
|
||||
1) _SHELL="/bin/sh";;
|
||||
2) _SHELL="$_DEFAULTLSHELL";;
|
||||
@@ -139,7 +164,6 @@ LdapUpdateShadowWarning () {
|
||||
echo "Updating password expiry to $_newWarning days"
|
||||
}
|
||||
|
||||
-
|
||||
# Since this setup script is meant to be a
|
||||
# wrapper on top of existing ldap scripts,
|
||||
# it share invoke those... we could have achieved
|
||||
@@ -170,10 +194,9 @@ if [ "$#" -eq 0 ]; then
|
||||
# prompt for sudo permissions
|
||||
if [ "$_SHELL" != "$_DEFAULTLSHELL" ]; then
|
||||
# Should sudo be activated for this user
|
||||
- echo -n "Add $_username to sudoer list? (yes/NO): "
|
||||
- read CONFIRM
|
||||
- CONFIRM=${CONFIRM,,}
|
||||
-
|
||||
+ shellInput="Add $_username to sudoer list? (yes/NO): "
|
||||
+ options=( "yes", "no" )
|
||||
+ CONFIRM=`LdapUserInput "$shellInput" options[@]`
|
||||
if is_yes $CONFIRM
|
||||
then
|
||||
LdapAddSudo "$_username"
|
||||
@@ -181,9 +204,9 @@ if [ "$#" -eq 0 ]; then
|
||||
fi
|
||||
|
||||
# Add to secondary user group
|
||||
- echo -n "Add $_username to secondary user group? (yes/NO): "
|
||||
- read CONFIRM
|
||||
- CONFIRM=${CONFIRM,,}
|
||||
+ shellInput="Add $_username to secondary user group? (yes/NO): "
|
||||
+ options=( "yes", "no" )
|
||||
+ CONFIRM=`LdapUserInput "$shellInput" options[@]`
|
||||
if is_yes $CONFIRM
|
||||
then
|
||||
echo -n "Secondary group to add user to? [$_DEFAULTGRP2]: "
|
@ -1,12 +1,17 @@
|
||||
---
|
||||
Makefile | 5
|
||||
man/man1/ldapusersetup.1 | 61 ++++++++++
|
||||
sbin/ldapusersetup | 263 +++++++++++++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 327 insertions(+), 2 deletions(-)
|
||||
Makefile | 5 +-
|
||||
man/man1/ldapusersetup.1 | 60 +++++++++++
|
||||
sbin/ldapusersetup | 254 +++++++++++++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 317 insertions(+), 2 deletions(-)
|
||||
create mode 100644 man/man1/ldapusersetup.1
|
||||
create mode 100644 sbin/ldapusersetup
|
||||
|
||||
diff --git a/sbin/ldapusersetup b/sbin/ldapusersetup
|
||||
new file mode 100644
|
||||
index 0000000..27d12dc
|
||||
--- /dev/null
|
||||
+++ b/sbin/ldapusersetup
|
||||
@@ -0,0 +1,263 @@
|
||||
@@ -0,0 +1,254 @@
|
||||
+#!/bin/sh
|
||||
+
|
||||
+# ldapusersetup : interactive setup for adding users to LDAP
|
||||
@ -33,7 +38,6 @@
|
||||
+ echo "Usage : $0 [-u <username | uid> <field> <value>]
|
||||
+where accepted field(s) are as follows:
|
||||
+--sudo : whether to add this user to sudoer list
|
||||
+--shell <\"bash\"|\"lshell\"> : choose the shell for this user (default is lshell)
|
||||
+--secondgroup <grp> : the secondary group to add this user to
|
||||
+--passmax <value> : the shadowMax value for this user
|
||||
+--passwarning <value> : the shadowWarning value for this user"
|
||||
@ -46,13 +50,36 @@
|
||||
+
|
||||
+# runtime defaults
|
||||
+_DEFAULTGRP2="wrs_protected"
|
||||
+_DEFAULTLSHELL="/usr/local/bin/cgcs_cli"
|
||||
+_BASHSHELL="/bin/bash"
|
||||
+_DEFAULTSHADOWMAX="90"
|
||||
+_DEFAULTSHADOWWARNING="2"
|
||||
+_SHELL=""
|
||||
+
|
||||
+### Helper functions ###
|
||||
+
|
||||
+# Gets input from user and validates it.
|
||||
+# Will only return if input meets validation
|
||||
+# criteria otherwise will just sit there.
|
||||
+#
|
||||
+# Input : input string ($1), valid output options ($2)
|
||||
+# Output: the validated input
|
||||
+# Note : the validation list must be an array
|
||||
+LdapUserInput () {
|
||||
+declare -a optionAry=("${!2}")
|
||||
+while true; do
|
||||
+ read -p "$1" _output
|
||||
+ # convert to lower case
|
||||
+ _output2=${_output,,}
|
||||
+ # check if output is a valid option
|
||||
+ if [[ "${optionAry[@]}" =~ "$_output2" ]]; then
|
||||
+ break
|
||||
+ else
|
||||
+ echo "Invalid input \"$_output\". Allowed options: ${optionAry[@]}" >&2
|
||||
+ fi
|
||||
+done
|
||||
+ echo "$_output2"
|
||||
+}
|
||||
+
|
||||
+# Delete an ldap user if it exists
|
||||
+# and exit with error
|
||||
+# Input : username ($1), exit msg ($2)
|
||||
@ -74,30 +101,8 @@
|
||||
+# Input : username ($1), shell to set ($2)
|
||||
+# Output : none
|
||||
+LdapAddLoginShell () {
|
||||
+ if [ -z "$2" ]; then
|
||||
+ # Ask the user for the login shell
|
||||
+ echo "Select Login Shell option # [2]:
|
||||
+1) Bash
|
||||
+2) Lshell"
|
||||
+ read opn
|
||||
+ case $opn in
|
||||
+ 1) _SHELL="/bin/sh";;
|
||||
+ 2) _SHELL="$_DEFAULTLSHELL";;
|
||||
+ *)
|
||||
+ [ ! -z "$opn" ] && echo "Invalid option. Selecting Lshell"
|
||||
+ _SHELL="$_DEFAULTLSHELL"
|
||||
+ ;;
|
||||
+ esac
|
||||
+ else
|
||||
+ shellopn=${$2,,}
|
||||
+ case $shellopn in
|
||||
+ "bash") _SHELL="/bin/sh";;
|
||||
+ "lshell") _SHELL="$_DEFAULTLSHELL";;
|
||||
+ *)
|
||||
+ echo "Invalid option($2). Selecting Lshell"; _SHELL="$_DEFAULTLSHELL"
|
||||
+ ;;
|
||||
+ esac
|
||||
+ fi
|
||||
+ # Support bash only now.
|
||||
+ _SHELL="$_BASHSHELL"
|
||||
+ # Replace the login shell
|
||||
+ ldapmodifyuser $1 replace loginShell $_SHELL &> /dev/null
|
||||
+ [ $? -eq 0 ] || LdapRollback $1 "Critical setup error: cannot set login shell"
|
||||
@ -148,14 +153,13 @@
|
||||
+ echo "Updating password expiry to $_newWarning days"
|
||||
+}
|
||||
+
|
||||
+
|
||||
+# Since this setup script is meant to be a
|
||||
+# wrapper on top of existing ldap scripts,
|
||||
+# it share invoke those... we could have achieved
|
||||
+# loose coupling by not relying on helpers but
|
||||
+# at the expense of massively redundant code
|
||||
+# duplication.
|
||||
+declare -a helper_scripts=("ldapadduser" "ldapaddsudo" "ldapmodifyuser" "ldapaddusertogroup" "$_DEFAULTLSHELL")
|
||||
+declare -a helper_scripts=("ldapadduser" "ldapaddsudo" "ldapmodifyuser" "ldapaddusertogroup" "$_BASHSHELL")
|
||||
+
|
||||
+# Do some quick sanity tests to make sure
|
||||
+# helper scripts are present
|
||||
@ -172,27 +176,23 @@
|
||||
+ read _username
|
||||
+ LdapAddUser "$_username"
|
||||
+
|
||||
+ # Replace the login shell. We will prompt the user for this
|
||||
+ # Replace the login shell. Only bash is supported now.
|
||||
+ LdapAddLoginShell "$_username"
|
||||
+
|
||||
+ # If login shell is NOT the default limited shell then
|
||||
+ # prompt for sudo permissions
|
||||
+ if [ "$_SHELL" != "$_DEFAULTLSHELL" ]; then
|
||||
+ # Should sudo be activated for this user
|
||||
+ echo -n "Add $_username to sudoer list? (yes/NO): "
|
||||
+ read CONFIRM
|
||||
+ CONFIRM=${CONFIRM,,}
|
||||
+ # Should sudo be activated for this user
|
||||
+ echo -n "Add $_username to sudoer list? (yes/NO): "
|
||||
+ read CONFIRM
|
||||
+ CONFIRM=${CONFIRM,,}
|
||||
+
|
||||
+ if is_yes $CONFIRM
|
||||
+ then
|
||||
+ LdapAddSudo "$_username"
|
||||
+ fi
|
||||
+ if is_yes $CONFIRM
|
||||
+ then
|
||||
+ LdapAddSudo "$_username"
|
||||
+ fi
|
||||
+
|
||||
+ # Add to secondary user group
|
||||
+ echo -n "Add $_username to secondary user group? (yes/NO): "
|
||||
+ read CONFIRM
|
||||
+ CONFIRM=${CONFIRM,,}
|
||||
+ shellInput="Add $_username to secondary user group? (yes/NO): "
|
||||
+ options=( "yes", "no" )
|
||||
+ CONFIRM=`LdapUserInput "$shellInput" options[@]`
|
||||
+ if is_yes $CONFIRM
|
||||
+ then
|
||||
+ echo -n "Secondary group to add user to? [$_DEFAULTGRP2]: "
|
||||
@ -226,10 +226,6 @@
|
||||
+ --sudo) # optional
|
||||
+ _sudo="yes"
|
||||
+ ;;
|
||||
+ --shell) # optional
|
||||
+ _loginshell="$2"
|
||||
+ shift
|
||||
+ ;;
|
||||
+ --passmax) # optional
|
||||
+ _shadowMax="$2"
|
||||
+ shift
|
||||
@ -270,9 +266,11 @@
|
||||
+ LdapUpdateShadowMax $_username $_shadowMax
|
||||
+ LdapUpdateShadowWarning $_username $_shadowWarning
|
||||
+fi
|
||||
diff --git a/Makefile b/Makefile
|
||||
index f81c272..6e5b193 100644
|
||||
--- a/Makefile
|
||||
+++ b/Makefile
|
||||
@@ -41,12 +41,13 @@ SBINFILES = ldapdeletemachine ldapmodify
|
||||
@@ -41,12 +41,13 @@ SBINFILES = ldapdeletemachine ldapmodifygroup ldapsetpasswd lsldap ldapadduser l
|
||||
ldapdeleteuser ldapsetprimarygroup ldapfinger ldapid ldapgid ldapmodifymachine \
|
||||
ldaprenamegroup ldapaddgroup ldapaddusertogroup ldapdeleteuserfromgroup \
|
||||
ldapinit ldapmodifyuser ldaprenamemachine ldapaddmachine ldapdeletegroup \
|
||||
@ -288,9 +286,12 @@
|
||||
MAN5FILES = ldapscripts.5
|
||||
TMPLFILES = ldapaddgroup.template.sample ldapaddmachine.template.sample \
|
||||
ldapadduser.template.sample
|
||||
diff --git a/man/man1/ldapusersetup.1 b/man/man1/ldapusersetup.1
|
||||
new file mode 100644
|
||||
index 0000000..9b3129b
|
||||
--- /dev/null
|
||||
+++ b/man/man1/ldapusersetup.1
|
||||
@@ -0,0 +1,61 @@
|
||||
@@ -0,0 +1,60 @@
|
||||
+.\" Copyright (c) 2015 Wind River Systems, Inc.
|
||||
+.\"
|
||||
+.\" This program is free software; you can redistribute it and/or
|
||||
@ -337,7 +338,6 @@
|
||||
+The name or uid of the user to modify.
|
||||
+The following fields are available as long format options:
|
||||
+--sudo : whether to add this user to sudoer list
|
||||
+--shell <bash | lshell> : which login shell to use (default is lshell)
|
||||
+--secondgroup <grp> : the secondary group to add this user to
|
||||
+--passmax <value> : the shadowMax value for this user
|
||||
+--passwarning <value> : the shadowWarning value for this user"
|
||||
|
Loading…
Reference in New Issue
Block a user