Files
ldapuserdir/bin/ldapuserdir-ctl
Derek Feichtinger c74b73594c introduced LdapUserDirError exception
instead of returning an empty string for a systemuser2dn lookup, now a
LdapUserDirError is returned.
2012-12-07 23:02:11 +01:00

335 lines
10 KiB
Python
Executable File

#!/usr/bin/python
import logging
from ldapuserdir import LdapUserDir, __version__ as libversion, LdapUserDirError
import ldap
import sys
import os
from optparse import OptionParser
import ConfigParser
import getpass
class MyOptParser(OptionParser):
"""OptionParser derived class for enabling us to give out a
nicer help text where text can follow the option section"""
def format_epilog(self, formatter):
return self.epilog.replace('%prog',os.path.basename(sys.argv[0]))
def read_cfg(filename):
cfg = ConfigParser.ConfigParser()
try:
mylogger.debug('reading config from %s' % filename)
cfg.read(filename)
config = {
'serverurl' : cfg.get('Ldap','serverurl'),
'user_ou' : cfg.get('Ldap','user_ou'),
'group_ou' : cfg.get('Ldap','group_ou'),
'default_user_dn' : cfg.get('Ldap','default_user_dn'),
'default_user_pw' : cfg.get('Ldap','default_user_pw'),
}
except Exception, err:
sys.stderr.write("Error in reading configuration from %s\n" % filename)
sys.stderr.write(str(err)+'\n')
sys.exit(1)
try:
config['default_group_filter'] = cfg.get('Ldap','default_group_filter')
except:
config['default_group_filter'] = '*'
return config
#Defaults
cfgfile_loc = [os.path.expanduser('~/.ldapuserdir-ctl.cfg'),
'/etc/ldapuserdir-ctl.cfg']
config = {
'serverurl' : 'ldaps://xyzdir.example.com:636',
'user_ou' : 'OU=Users,DC=example.com,DC=ch',
'group_ou' : 'OU=Groups,DC=example.com,DC=ch',
'default_user_dn' : 'CN=minpriv_user,OU=Services,DC=example.com,DC=ch',
'default_user_pw' : 'dummypwd',
'default_group_filter' : 'svc-ra*'
}
flag_needprivileges = False
userfilter = '-'
user_pw = ''
mode = 'list'
mylogger = logging.getLogger(os.path.basename(sys.argv[0]))
mylogger.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(name)s %(levelname)s: %(message)s')
ch = logging.StreamHandler()
ch.setLevel(logging.WARNING)
ch.setFormatter(formatter)
mylogger.addHandler(ch)
################################################
# OPTION PARSING
usage = """%prog [options] groupname [usernames]
Used to inspect or change members of a group in Active Directory
User names can be given as full distinguished names or just as
the short names (in that case they will be extended by the
standard OU extension)
The configuration is read from a configuration file (default
locations:
"""
usage += ", ".join(cfgfile_loc) + ')\n'
usage_epilog = """
Examples:
List group members
%prog svc_ra_x06sa
%prog 'svc_ra_*'
Get group memberships for user mueller
%prog -g mueller
Add/delete users to/from a group (requires access rights!)
%prog -a svc_ra_x06sa user1 user2 user3
%prog -d svc_ra_x06sa user1 user2
List users matching a pattern
%prog -u 'mueller*'
"""
examplecfg = """# Configuration file example:
[Ldap]
# URL for contacting the LDAP server
serverurl = ldaps://d.psi.ch:636
# base ldap path under which all users are found
user_ou = OU=Users,OU=PSI,DC=d,DC=psi,DC=ch
# base ldap path under which groups are found
group_ou = ou=Groups,ou=PSI,dc=d,dc=psi,dc=ch
# minimally privileged Ldap user and password for running normal
# lookup queries
default_user_dn = CN=linux_ldap,OU=Services,OU=IT,DC=d,DC=psi,DC=ch
default_user_pw = DEFaultPassword
# Optional:
# default filter to be used for group searches
default_group_filter = svc-ra*
"""
#parser = OptionParser(usage = usage, epilog = usage_epilog)
parser = MyOptParser(usage = usage, epilog = usage_epilog)
parser.add_option('-a',
action = 'store_true',
dest = 'flag_add',
help = 'add group members',
)
parser.add_option('-d',
action = 'store_true',
dest = 'flag_del',
help = 'delete group members',
)
parser.add_option('-c',
action = 'store',
dest = 'cfgfile',
help = 'path of a config file',
default = ''
)
parser.add_option('--configfile',
action = 'store_true',
dest = 'flag_examplecfg',
help = 'show an example configuration file',
default= False
)
parser.add_option('-u',
action = 'store',
dest = 'userfilter',
help = 'list all matching ldap users that have defined unix mappings',
)
parser.add_option('--debug',
action = 'store_true',
dest = 'flag_debug',
help = 'debug mode: log messages at debug level',
)
parser.add_option('-D',
action = 'store',
dest = 'user_dn',
help = 'DN or CN of ldap user for binding to the AD server (%s)' % config['default_user_dn'],
default = None
)
parser.add_option('-f',
action = 'store',
dest = 'pwfile',
help = 'path to password file (without this pwd will be prompted for)',
default = ''
)
parser.add_option('-g',
action = 'store',
dest = 'user_to_group',
help = 'get group memberships for this user',
default = ''
)
parser.add_option('-v',
action = 'store_true',
dest = 'flag_verbose',
help = 'use more verbose output (with user list only)',
default = False
)
parser.add_option('--user-ou',
action = 'store',
dest = 'user_ou',
help = 'default OU for users (%s)' % config['user_ou'],
default = None
)
parser.add_option('--group-ou',
action = 'store',
dest = 'group_ou',
help = 'default OU for groups (%s)' % config['group_ou'],
default = None
)
parser.add_option('--no-msSFU',
action = 'store_true',
dest = 'flag_nosfu',
help = 'do not restrict to entries with unix (msSFU) mappings',
default = False
)
parser.add_option('-V',
action = 'store_true',
dest = 'flag_version',
help = 'show version information',
default = False
)
(options, args) = parser.parse_args()
group = None
usernames = []
if len(args) > 0:
group = args.pop(0)
usernames = args
if options.flag_debug:
ch.setLevel(logging.DEBUG)
if options.flag_version:
sys.stdout.write('Library version: ' + libversion + '\n')
sys.exit(0)
if options.flag_examplecfg:
sys.stdout.write(examplecfg)
sys.exit(0)
cfgfile = None
if(options.cfgfile != ''):
cfgfile = options.cfgfile
else:
for tmp in cfgfile_loc:
if os.path.exists(tmp):
cfgfile = tmp
break;
if cfgfile == None:
sys.stderr.write('Error: You must provide a config file (default locations '
+ ', '.join(cfgfile_loc) + ' or explicitely)\n')
sys.exit(1)
config = read_cfg(cfgfile)
user_dn = config['default_user_dn']
if options.user_dn:
config['user_dn'] = options.user_dn
if options.group_ou:
config['group_ou'] = options.group_ou
if options.user_ou:
config['user_ou'] = options.user_ou
flag_verbose = options.flag_verbose
flag_sfu = not options.flag_nosfu
userfilter = options.userfilter
if options.flag_del:
mode = 'del'
flag_needprivileges = True
if options.flag_add:
mode = 'add'
flag_needprivileges = True
if userfilter:
mode = 'userlist'
if options.user_to_group:
mode = "user_to_group"
user_to_group = options.user_to_group
if (mode == 'add' or mode == 'del') and len(usernames) == 0:
sys.stderr.write("Error: Not enough arguments\n")
sys.exit(1)
if ',' not in user_dn:
user_dn = 'CN=' + user_dn + ',' + user_ou
if flag_needprivileges and user_dn == config['default_user_dn']:
try:
l_unpriv = LdapUserDir(config['serverurl'],
config['default_user_dn'],
config['default_user_pw'],
user_ou = config['user_ou'],
logger = mylogger)
user_dn = l_unpriv.systemuser2dn(os.getlogin())
if user_dn == '':
sys.stderr.write('Error: Need priviledged user and cannot map your system user "%s" to LDAP DN for binding (you may want to use explicit -D user_dn option?)' % os.getlogin() )
sys.exit(1)
except ldap.LDAPError, e:
sys.stderr.write('LDAP error: %s\n' % str(e))
sys.exit(1)
if user_dn == config['default_user_dn']:
user_pw = config['default_user_pw']
if options.pwfile != '':
pwf = open(options.pwfile)
user_pw = pwf.readline().rstrip('\n')
if user_pw == '':
user_pw = getpass.getpass()
if user_pw == '':
sys.stderr.write('Error: No empty passwd allowed\n')
# Note: AD accepts empty passwds, but will give anonymous access
# So, we want to catch that case
sys.exit(1)
try:
l = LdapUserDir(config['serverurl'],
user_dn,
user_pw,
config['group_ou'],
config['user_ou'],
sfu = flag_sfu,
logger=mylogger)
if mode == 'list':
sfilter = config['default_group_filter']
if group:
sfilter = group
l.list_groups(sfilter)
elif mode == 'userlist':
l.list_users_etcpwd(userfilter, verbose = flag_verbose)
elif mode == 'user_to_group':
try:
sys.stdout.write("\n".join(l.get_groups_for_user(user_to_group))
+ "\n")
except LdapUserDirError, err:
sys.stderr.write('Error: ' + str(err) +'\n')
sys.exit(1)
elif mode == 'add':
l.add_groupmembers(group, usernames)
elif mode == 'del':
l.del_groupmembers(group, usernames)
except ldap.INVALID_CREDENTIALS, e:
sys.exit(1)
except ldap.LDAPError, e:
sys.stderr.write('Unhandled LDAP error: %s\n' % str(e))
sys.exit(1)
except Exception, err:
sys.stderr.write('Unhandled Exception (%s): %s\n' % (type(err), str(err)))
sys.exit(1)
sys.exit(0)