Source code for univention.admincli.adduser

# -*- coding: utf-8 -*-
#
# Copyright 2004-2022 Univention GmbH
#
# https://www.univention.de/
#
# All rights reserved.
#
# The source code of this program is made available
# under the terms of the GNU Affero General Public License version 3
# (GNU AGPL V3) as published by the Free Software Foundation.
#
# Binary versions of this program provided by Univention to you as
# well as other copyrighted, protected or trademarked materials like
# Logos, graphics, fonts, specific documentations and configurations,
# cryptographic keys etc. are subject to a license agreement between
# you and Univention and not subject to the GNU AGPL V3.
#
# In the case you use this program under the terms of the GNU AGPL V3,
# the program is provided in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public
# License with the Debian GNU/Linux or Univention distribution in file
# /usr/share/common-licenses/AGPL-3; if not, see
# <https://www.gnu.org/licenses/>.

"""
adduser part for the command line interface
"""

import os
import getopt
import subprocess

import six
from ldap.filter import filter_format

import univention.debug as ud
import univention.config_registry
import univention.admin.uldap
import univention.admin.config
import univention.admin.modules
import univention.admin.objects
import univention.admin.handlers.users.user
import univention.admin.handlers.groups.group
import univention.admin.handlers.computers.windows


[docs]def status(msg): # univention-adduser is called by Samba when doing "vampire." Since # vampire produces a lot of output, and we'd like to print a moderate # log, we prepend UNIVENTION to our output. That way we can identify # distinguish them from all of Samba's log messages out = 'UNIVENTION %s' % (msg.encode('utf-8') if six.PY2 else msg,) return out
[docs]def nscd_invalidate(table): if table: ud.debug(ud.ADMIN, ud.INFO, 'NSCD: --invalidate %s' % (table,)) try: subprocess.check_call(['/usr/sbin/nscd', '--invalidate', table], close_fds=True) except (EnvironmentError, subprocess.CalledProcessError): ud.debug(ud.ADMIN, ud.INFO, 'NSCD: failed') else: ud.debug(ud.ADMIN, ud.INFO, 'NSCD: ok')
[docs]def get_user_object(user, position, lo): try: # user Account return univention.admin.modules.lookup(univention.admin.handlers.users.user, None, lo, scope='domain', base=position.getDn(), filter=filter_format(u'(username=%s)', [user]), required=True, unique=True)[0] except Exception: # machine Account for handler in [univention.admin.handlers.computers.windows, univention.admin.handlers.computers.domaincontroller_master, univention.admin.handlers.computers.domaincontroller_slave, univention.admin.handlers.computers.domaincontroller_backup, univention.admin.handlers.computers.memberserver]: try: return univention.admin.modules.lookup(handler, None, lo, scope='domain', base=position.getDn(), filter=filter_format(u'(uid=%s)', [user]), required=True, unique=True)[0] except Exception: continue return 'ERROR: account not found, nothing modified'
def _decode(args): for arg in args: try: yield arg.decode('utf-8') except UnicodeDecodeError: yield arg.decode('latin-1')
[docs]def doit(arglist): ud.init('/var/log/univention/directory-manager-cmd.log', ud.FLUSH, ud.FUNCTION) out = [] configRegistry = univention.config_registry.ConfigRegistry() configRegistry.load() op = 'add' scope = 'user' cmd = os.path.basename(arglist[0]) if cmd == 'univention-addgroup': scope = 'group' op = 'add' elif cmd == 'univention-deluser': scope = 'user' op = 'del' elif cmd == 'univention-delgroup': scope = 'group' op = 'del' elif cmd == 'univention-addmachine': scope = 'machine' op = 'add' elif cmd == 'univention-delmachine': scope = 'machine' op = 'del' elif cmd == 'univention-setprimarygroup': scope = 'user' op = 'primarygroup' opts, args = getopt.getopt(arglist[1:], '', ['status-fd=', 'status-fifo=']) try: lo, position = univention.admin.uldap.getAdminConnection() except Exception as exc: ud.debug(ud.ADMIN, ud.WARN, 'authentication error: %s' % (exc,)) try: lo, position = univention.admin.uldap.getMachineConnection() except Exception as exc2: ud.debug(ud.ADMIN, ud.WARN, 'authentication error: %s' % (exc2,)) out.append('authentication error: %s' % (exc,)) out.append('authentication error: %s' % (exc2,)) return out if six.PY2: args = list(_decode(args)) univention.admin.modules.update() if len(args) == 1: if scope == 'machine': machine = args[0] if machine.endswith('$'): machine = machine[:-1] if configRegistry.get('samba/defaultcontainer/computer'): position.setDn(configRegistry['samba/defaultcontainer/computer']) else: position.setDn(univention.admin.config.getDefaultContainer(lo, 'computers/windows')) elif scope == 'group': group = args[0] if configRegistry.get('samba/defaultcontainer/group'): position.setDn(configRegistry['samba/defaultcontainer/group']) else: position.setDn(univention.admin.config.getDefaultContainer(lo, 'groups/group')) else: user = args[0] if configRegistry.get('samba/defaultcontainer/user'): position.setDn(configRegistry['samba/defaultcontainer/user']) else: position.setDn(univention.admin.config.getDefaultContainer(lo, 'users/user')) action = op + scope elif len(args) == 2: user, group = args if op == 'del': action = 'deluserfromgroup' elif op == 'primarygroup': action = 'setprimarygroup' else: action = 'addusertogroup' else: return out if action == 'adduser': out.append(status(u'Adding user %s' % (user,))) object = univention.admin.handlers.users.user.object(None, lo, position=position) object.open() object['username'] = user object['lastname'] = user.encode('utf-8').decode('ASCII') object['password'] = subprocess.check_output(['/usr/bin/makepasswd', '--minchars=8'], close_fds=True).strip().decode('ASCII', 'ignore') object['primaryGroup'] = univention.admin.config.getDefaultValue(lo, 'group') object.create() nscd_invalidate('passwd') elif action == 'deluser': out.append(status(u'Removing user %s' % (user,))) object = univention.admin.modules.lookup(univention.admin.handlers.users.user, None, lo, scope='domain', base=position.getDomain(), filter=filter_format(u'(username=%s)', [user]), required=True, unique=True)[0] object.open() object.remove() nscd_invalidate('passwd') elif action == 'addgroup': out.append(status(u'Adding group %s' % (group,))) object = univention.admin.handlers.groups.group.object(None, lo, position=position) object.open() object.options = ['posix'] object['name'] = group object.create() nscd_invalidate('group') elif action == 'delgroup': out.append(status(u'Removing group %s' % (group,))) object = univention.admin.modules.lookup(univention.admin.handlers.groups.group, None, lo, scope='domain', base=position.getDomain(), filter=filter_format(u'(name=%s)', [group]), required=True, unique=True)[0] object.open() object.remove() nscd_invalidate('group') elif action == 'addusertogroup': if group in configRegistry.get('samba/addusertogroup/filter/group', '').split(','): out.append(status(u'addusertogroup: filter protects group "%s"' % (group,))) return out out.append(status(u'Adding user %s to group %s' % (user, group))) groupobject = univention.admin.modules.lookup(univention.admin.handlers.groups.group, None, lo, scope='domain', base=position.getDn(), filter=filter_format(u'(name=%s)', [group]), required=True, unique=True)[0] groupobject.open() userobject = get_user_object(user, position, lo) if isinstance(userobject, six.string_types): out.append(userobject) return out if userobject.dn not in groupobject['users']: if groupobject['users'] == [''] or groupobject['users'] == []: groupobject['users'] = [userobject.dn] else: groupobject['users'].append(userobject.dn) groupobject.modify() nscd_invalidate('group') elif action == 'deluserfromgroup': out.append(status(u'Removing user %s from group %s' % (user, group))) groupobject = univention.admin.modules.lookup(univention.admin.handlers.groups.group, None, lo, scope='domain', base=position.getDn(), filter=filter_format(u'(name=%s)', [group]), required=True, unique=True)[0] groupobject.open() userobject = get_user_object(user, position, lo) if isinstance(userobject, six.string_types): out.append(userobject) return out userobject.open() if userobject.dn in groupobject['users'] and userobject['primaryGroup'] != groupobject.dn: groupobject['users'].remove(userobject.dn) groupobject.modify() nscd_invalidate('group') elif action == 'addmachine': out.append(status(u'Adding machine %s' % (machine,))) object = univention.admin.handlers.computers.windows.object(None, lo, position=position) object.open() object.options = ['posix'] object['name'] = machine object['primaryGroup'] = univention.admin.config.getDefaultValue(lo, 'computerGroup') object.create() nscd_invalidate('hosts') nscd_invalidate('passwd') elif action == 'delmachine': out.append(status(u'Removing machine %s' % (machine,))) object = univention.admin.modules.lookup(univention.admin.handlers.computers.windows, None, lo, scope='domain', base=position.getDomain(), filter=filter_format(u'(name=%s)', [machine]), required=True, unique=True)[0] object.open() object.remove() nscd_invalidate('hosts') elif action == 'setprimarygroup': out.append(status(u'Set primary group %s for user %s' % (group, user))) try: groupobject = univention.admin.modules.lookup(univention.admin.handlers.groups.group, None, lo, scope='domain', base=position.getDn(), filter=filter_format(u'(name=%s)', [group]), required=True, unique=True)[0] except Exception: out.append('ERROR: group not found, nothing modified') return out groupobject.open() userobject = get_user_object(user, position, lo) if isinstance(userobject, six.string_types): out.append(userobject) return out if 'samba' in userobject.options: userobject.options.remove('samba') userobject.open() if userobject.has_property('primaryGroup'): userobject['primaryGroup'] = groupobject.dn elif userobject.has_property('machineAccountGroup'): userobject['machineAccountGroup'] = groupobject.dn else: out.append('ERROR: unknown group attribute, nothing modified') return out userobject.modify() if userobject.dn not in groupobject['users']: groupobject['users'].append(userobject.dn) groupobject.modify() nscd_invalidate('group') nscd_invalidate('passwd') return out
if __name__ == '__main__': import sys print('\n'.join(doit(sys.argv)))