Added "csc-chsh" and "csc-chfn" utilities.
This commit is contained in:
parent
9097dd8738
commit
8c8e748ca8
|
@ -0,0 +1,153 @@
|
|||
#!/usr/bin/python2.4 --
|
||||
"""
|
||||
chfn - change real user name and information
|
||||
|
||||
This utility imitates chfn(1) from the shadow password suite, but makes its
|
||||
changes in the LDAP directory rather than in the passwd file.
|
||||
|
||||
When run from an unprivileged account, authentication will be performed
|
||||
before the account information is changed.
|
||||
"""
|
||||
import os, sys, pwd, getopt, PAM
|
||||
|
||||
safe_environment = ['LOGNAME', 'USERNAME', 'USER', 'HOME', 'TERM', 'LANG'
|
||||
'LC_ALL', 'LC_COLLATE', 'LC_CTYPE', 'LC_MESSAGES', 'LC_MONETARY',
|
||||
'LC_NUMERIC', 'LC_TIME', 'UID', 'GID', 'SSH_CONNECTION', 'SSH_AUTH_SOCK',
|
||||
'SSH_CLIENT']
|
||||
|
||||
for key in os.environ.keys():
|
||||
if key not in safe_environment:
|
||||
del os.environ[key]
|
||||
|
||||
os.environ['PATH'] = '/usr/sbin:/usr/bin:/sbin:/bin'
|
||||
|
||||
for pathent in sys.path[:]:
|
||||
if not pathent.find('/usr') == 0:
|
||||
sys.path.remove(pathent)
|
||||
|
||||
from csc.common.excep import InvalidArgument
|
||||
from csc.adm import accounts
|
||||
|
||||
progname = os.path.basename(sys.argv[0])
|
||||
|
||||
OPTION_MAP = {
|
||||
'-f': 'fullname',
|
||||
'-r': 'roomnumber',
|
||||
'-w': 'workphone',
|
||||
'-h': 'homephone',
|
||||
'-o': 'other'
|
||||
}
|
||||
LONG_NAMES = [
|
||||
('fullname', 'Full Name'),
|
||||
('roomnumber', 'Room Number'),
|
||||
('workphone', 'Work Phone'),
|
||||
('homephone', 'Home Phone'),
|
||||
('other', 'Other')
|
||||
]
|
||||
READONLY_FIELDS = [ 'fullname', 'other' ]
|
||||
|
||||
def usage():
|
||||
umesg = "Usage: %s [-f full name] [-r room no] [-w work ph] " + \
|
||||
"[-h home ph] [-o other] [user]"
|
||||
print umesg % progname
|
||||
sys.exit(2)
|
||||
|
||||
|
||||
def whoami():
|
||||
uid = os.getuid()
|
||||
username = os.getlogin()
|
||||
if pwd.getpwnam(username).pw_uid != uid:
|
||||
username = pwd.getpwuid(uid).pw_name
|
||||
return (uid, username)
|
||||
|
||||
def authenticate(username):
|
||||
auth = PAM.pam()
|
||||
auth.start('chsh', username)
|
||||
try:
|
||||
auth.authenticate()
|
||||
auth.acct_mgmt()
|
||||
except PAM.error, resp:
|
||||
print "%s: %s" % (progname, resp.args[0])
|
||||
sys.exit(1)
|
||||
|
||||
def main():
|
||||
|
||||
pwuid, pwnam = whoami()
|
||||
|
||||
gecos_params = {}
|
||||
|
||||
try:
|
||||
options, arguments = getopt.gnu_getopt(sys.argv[1:], 'f:r:w:h:o:')
|
||||
for opt, val in options:
|
||||
gecos_params[OPTION_MAP[opt]] = val
|
||||
if len(arguments) > 1:
|
||||
usage()
|
||||
elif len(arguments) == 1:
|
||||
username = arguments[0]
|
||||
else:
|
||||
username = pwnam
|
||||
except getopt.GetoptError, e:
|
||||
usage()
|
||||
|
||||
for field in READONLY_FIELDS:
|
||||
if field in gecos_params and pwuid:
|
||||
print "%s: Permission denied." % progname
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
if pwuid and pwd.getpwnam(username).pw_uid != pwuid:
|
||||
print "%s: Permission denied." % progname
|
||||
sys.exit(1)
|
||||
except KeyError:
|
||||
print "%s: unknown user %s" % (progname, username)
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
accounts.connect()
|
||||
gecos_raw = accounts.get_gecos(username)
|
||||
gecos = accounts.parse_gecos(gecos_raw)
|
||||
|
||||
if pwuid:
|
||||
authenticate(username)
|
||||
|
||||
if not gecos_params:
|
||||
print "Changing the user information for %s" % username
|
||||
print "Enter the new value, or press ENTER for the default"
|
||||
for field, longname in LONG_NAMES:
|
||||
if pwuid and field == 'other' and 'other' in READONLY_FIELDS:
|
||||
continue
|
||||
if gecos[field] is None:
|
||||
gecos[field] = ""
|
||||
if field in READONLY_FIELDS and pwuid:
|
||||
print " %s: %s" % (longname, gecos[field])
|
||||
else:
|
||||
print " %s: [%s]:" % (longname, gecos[field]),
|
||||
new_value = raw_input()
|
||||
if new_value:
|
||||
gecos[field] = new_value.strip()
|
||||
else:
|
||||
gecos.update(gecos_params)
|
||||
|
||||
gecos_raw_new = accounts.build_gecos(**gecos)
|
||||
if gecos_raw != gecos_raw_new:
|
||||
accounts.update_gecos(username, gecos_raw_new)
|
||||
|
||||
except InvalidArgument, e:
|
||||
longnames = dict(LONG_NAMES)
|
||||
longname = longnames.get(e.argname, e.argname).lower()
|
||||
print "%s: invalid %s: %s" % (progname, longname, e.argval)
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
exceps = ( accounts.ConfigurationException, accounts.LDAPException,
|
||||
accounts.KrbException, accounts.AccountException )
|
||||
try:
|
||||
main()
|
||||
except KeyboardInterrupt:
|
||||
sys.exit(130)
|
||||
except IOError, e:
|
||||
print "%s: %s: %s" % (progname, e.filename, e.strerror)
|
||||
sys.exit(1)
|
||||
except exceps, e:
|
||||
print "%s: %s" % (progname, e)
|
||||
sys.exit(1)
|
|
@ -0,0 +1,118 @@
|
|||
#!/usr/bin/python2.4 --
|
||||
"""
|
||||
chsh - change login shell
|
||||
|
||||
This utility imitates chsh(1) from the shadow password suite, but makes its
|
||||
changes in the LDAP directory rather than in the passwd file.
|
||||
|
||||
When run from an unprivileged account, authentication will be performed
|
||||
before the shell is changed, and the new shell must be listed in /etc/shells.
|
||||
"""
|
||||
import os, sys, pwd, getopt, PAM
|
||||
|
||||
safe_environment = ['LOGNAME', 'USERNAME', 'USER', 'HOME', 'TERM', 'LANG'
|
||||
'LC_ALL', 'LC_COLLATE', 'LC_CTYPE', 'LC_MESSAGES', 'LC_MONETARY',
|
||||
'LC_NUMERIC', 'LC_TIME', 'UID', 'GID', 'SSH_CONNECTION', 'SSH_AUTH_SOCK',
|
||||
'SSH_CLIENT']
|
||||
|
||||
for key in os.environ.keys():
|
||||
if key not in safe_environment:
|
||||
del os.environ[key]
|
||||
|
||||
os.environ['PATH'] = '/usr/sbin:/usr/bin:/sbin:/bin'
|
||||
|
||||
for pathent in sys.path[:]:
|
||||
if not pathent.find('/usr') == 0:
|
||||
sys.path.remove(pathent)
|
||||
|
||||
from csc.common.excep import InvalidArgument
|
||||
from csc.adm import accounts
|
||||
|
||||
progname = os.path.basename(sys.argv[0])
|
||||
|
||||
def usage():
|
||||
print "Usage: %s [-s shell] [username]" % progname
|
||||
sys.exit(2)
|
||||
|
||||
def whoami():
|
||||
uid = os.getuid()
|
||||
username = os.getlogin()
|
||||
if pwd.getpwnam(username).pw_uid != uid:
|
||||
username = pwd.getpwuid(uid).pw_name
|
||||
return (uid, username)
|
||||
|
||||
def authenticate(username):
|
||||
auth = PAM.pam()
|
||||
auth.start('chsh', username)
|
||||
try:
|
||||
auth.authenticate()
|
||||
auth.acct_mgmt()
|
||||
except PAM.error, resp:
|
||||
print "%s: %s" % (progname, resp.args[0])
|
||||
sys.exit(1)
|
||||
|
||||
def main():
|
||||
|
||||
pwuid, pwnam = whoami()
|
||||
|
||||
try:
|
||||
options, arguments = getopt.gnu_getopt(sys.argv[1:], 's:')
|
||||
new_shell = None
|
||||
for opt, val in options:
|
||||
if opt == '-s':
|
||||
new_shell = val
|
||||
if len(arguments) > 1:
|
||||
usage()
|
||||
elif len(arguments) == 1:
|
||||
username = arguments[0]
|
||||
else:
|
||||
username = pwnam
|
||||
except getopt.GetoptError, e:
|
||||
usage()
|
||||
|
||||
try:
|
||||
if pwuid and pwd.getpwnam(username).pw_uid != pwuid:
|
||||
print "%s: You may not change the shell for %s." % (progname, username)
|
||||
sys.exit(1)
|
||||
except KeyError:
|
||||
print "%s: unknown user %s" % (progname, username)
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
accounts.connect()
|
||||
current_shell = accounts.get_shell(username)
|
||||
|
||||
if pwuid:
|
||||
authenticate(username)
|
||||
|
||||
if not new_shell:
|
||||
print "Changing the login shell for %s" % username
|
||||
print "Enter the new value, or press ENTER for the default"
|
||||
print " Login Shell [%s]:" % current_shell,
|
||||
new_shell = raw_input()
|
||||
if not new_shell:
|
||||
new_shell = current_shell
|
||||
|
||||
if new_shell != current_shell:
|
||||
accounts.update_shell(username, new_shell, pwuid != 0)
|
||||
|
||||
except InvalidArgument, e:
|
||||
if e.argname == 'shell':
|
||||
print "%s: %s: invalid shell" % (progname, new_shell)
|
||||
sys.exit(1)
|
||||
else:
|
||||
raise
|
||||
|
||||
if __name__ == '__main__':
|
||||
exceps = ( accounts.ConfigurationException, accounts.LDAPException,
|
||||
accounts.KrbException, accounts.AccountException )
|
||||
try:
|
||||
main()
|
||||
except KeyboardInterrupt:
|
||||
sys.exit(130)
|
||||
except IOError, e:
|
||||
print "%s: %s: %s" % (progname, e.filename, e.strerror)
|
||||
sys.exit(1)
|
||||
except exceps, e:
|
||||
print "%s: %s" % (progname, e)
|
||||
sys.exit(1)
|
|
@ -412,7 +412,7 @@ def update_shell(username, shell, check=True):
|
|||
|
||||
# reject nonexistent or nonexecutable shells
|
||||
if not os.access(shell, os.X_OK) or not os.path.isfile(shell):
|
||||
raise InvalidArgument("shell", shell, "is not a regular executable file")
|
||||
raise InvalidArgument("shell", shell, "not an executable file")
|
||||
|
||||
if check:
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ def read(filename, included=None):
|
|||
included - files previously read (internal)
|
||||
|
||||
Exceptions:
|
||||
ConfigurationException - when the configuration file cannot be read
|
||||
IOError - when the configuration file cannot be read
|
||||
"""
|
||||
|
||||
if not included:
|
||||
|
@ -75,10 +75,7 @@ def read(filename, included=None):
|
|||
return {}
|
||||
included.append(filename)
|
||||
|
||||
try:
|
||||
conffile = open(filename)
|
||||
except IOError:
|
||||
raise ConfigurationException('unable to read configuration file: "%s"' % filename)
|
||||
conffile = open(filename)
|
||||
|
||||
options = {}
|
||||
|
||||
|
|
Loading…
Reference in New Issue