diff --git a/base/univention-lib/debian/control b/base/univention-lib/debian/control
index a8b100e..1370824 100644
--- a/base/univention-lib/debian/control
+++ b/base/univention-lib/debian/control
@@ -21,7 +21,8 @@ Depends: ${python:Depends},
python-ldb,
python-samba,
python-ldap,
- python-imaging
+ python-imaging,
+ python-univention-lib-umc,
Provides: ${python:Provides}
Description: UCS - common scripting functions for Python scripts
This package contains Python functions used by various
@@ -37,6 +38,7 @@ Architecture: all
Depends: ${misc:Depends},
python-univention-config-registry (>= 10.0.0-1),
python-univention-lib (= ${binary:Version}),
+ shell-univention-lib-umc,
pwgen
Description: UCS - common scripting functions for shell scripts
This package contains shell functions used by various
diff --git a/base/univention-lib/python/umc_connection.py b/base/univention-lib/python/umc_connection.py
deleted file mode 100644
index 65c6d05..0000000
--- a/base/univention-lib/python/umc_connection.py
+++ /dev/null
@@ -1,148 +0,0 @@
-#!/usr/bin/python2.7
-# -*- coding: utf-8 -*-
-#
-# Univention Common Python Library
-# Connections to remote UMC Servers
-#
-# Copyright 2013-2016 Univention GmbH
-#
-# http://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
-# .
-
-from httplib import HTTPSConnection, HTTPException
-from json import loads, dumps
-from socket import error as SocketError
-
-from univention.config_registry import ConfigRegistry
-ucr = ConfigRegistry()
-ucr.load()
-
-
-class UMCConnection(object):
-
- def __init__(self, host, username=None, password=None, error_handler=None):
- self._host = host
- self._headers = {
- 'Content-Type': 'application/json; charset=UTF-8',
- 'Accept': 'application/json; q=1, text/html; q=0.5; */*; q=0.1',
- 'X-Requested-With': 'XMLHttpRequest',
- }
- self._error_handler=error_handler
- if username is not None:
- self.auth(username, password)
-
- def get_connection(self):
- '''Creates a new HTTPSConnection to the host'''
- # once keep-alive is over, the socket closes
- # so create a new connection on every request
- return HTTPSConnection(self._host)
-
- @classmethod
- def get_machine_connection(cls, error_handler=None):
- '''Creates a connection with the credentials of the local host
- to the DC Master'''
- username = '%s$' % ucr.get('hostname')
- password = ''
- try:
- with open('/etc/machine.secret') as machine_file:
- password = machine_file.readline().strip()
- except (OSError, IOError) as e:
- if error_handler:
- error_handler('Could not read /etc/machine.secret: %s' % e)
- try:
- connection = cls(ucr.get('ldap/master'))
- connection.auth(username, password)
- return connection
- except (HTTPException, SocketError) as e:
- if error_handler:
- error_handler('Could not connect to UMC on %s: %s' % (ucr.get('ldap/master'), e))
- return None
-
- def auth(self, username, password, auth_type=None):
- '''Tries to authenticate against the host and preserves the
- cookie. Has to be done only once (but keep in mind that the
- session probably expires after 10 minutes of inactivity)'''
- data = self.build_data({'username' : username, 'password' : password, 'auth_type': auth_type})
- con = self.get_connection()
- try:
- con.request('POST', '/umcp/auth', data, headers=self._headers)
- except Exception as e:
- # probably unreachable
- if self._error_handler:
- self._error_handler(str(e))
- error_message = '%s: Authentication failed while contacting: %s' % (self._host, e)
- raise HTTPException(error_message)
- else:
- try:
- response = con.getresponse()
- cookie = response.getheader('set-cookie')
- if cookie is None:
- raise ValueError('No cookie')
- self._headers['Cookie'] = cookie # FIXME: transform Set-Cookie to Cookie
- except Exception as e:
- if self._error_handler:
- self._error_handler(str(e))
- error_message = '%s: Authentication failed: %s' % (self._host, response.read())
- raise HTTPException(error_message)
-
- def build_data(self, data, flavor=None):
- '''Returns a dictionary as expected by the UMC Server'''
- data = {'options' : data}
- if flavor:
- data['flavor'] = flavor
- return dumps(data)
-
- def request(self, url, data=None, flavor=None, command='command'):
- '''Sends a request and returns the data from the response. url
- as in the XML file of that UMC module.
- command may be anything that UMCP understands, especially:
- * command (default)
- * get (and url could be 'ucr' then)
- * set (and url would be '' and data could be {'locale':'de_DE'})
- * upload (url could be 'udm/license/import')
- '''
- if data is None:
- data = {}
- data = self.build_data(data, flavor)
- con = self.get_connection()
- umcp_command = '/umcp/%s' % command
- if url:
- umcp_command = '%s/%s' % (umcp_command, url)
- con.request('POST', umcp_command, data, headers=self._headers)
- response = con.getresponse()
- if response.status != 200:
- error_message = '%s on %s (%s): %s' % (response.status, self._host, url, response.read())
- if response.status == 403:
- # 403 is either command is unknown
- # or command is known but forbidden
- if self._error_handler:
- self._error_handler(error_message)
- raise NotImplementedError('command forbidden: %s' % url)
- raise HTTPException(error_message)
- content = response.read()
- content = loads(content) # FIXME: inspect Content-Type response header
- if isinstance(content, dict):
- return content.get('result', content)
- return content
diff --git a/base/univention-lib/python/umc_module.py b/base/univention-lib/python/umc_module.py
deleted file mode 100644
index 2f93295..0000000
--- a/base/univention-lib/python/umc_module.py
+++ /dev/null
@@ -1,73 +0,0 @@
-import univention.admin.uexceptions
-import bz2
-import zlib
-from PIL import Image
-import StringIO
-import magic
-MIME_TYPE = magic.open(magic.MAGIC_MIME_TYPE)
-MIME_TYPE.load()
-MIME_DESCRIPTION = magic.open(magic.MAGIC_NONE)
-MIME_DESCRIPTION.load()
-
-UMC_ICON_BASEDIR = "/usr/share/univention-management-console-frontend/js/dijit/themes/umc/icons"
-
-compression_mime_type_handlers = {
- "application/x-gzip": lambda x: zlib.decompress(x, 16+zlib.MAX_WBITS),
- "application/x-bzip2": bz2.decompress
-}
-
-def get_mime_type(data):
- return MIME_TYPE.buffer(data)
-
-def get_mime_description(data):
- return MIME_DESCRIPTION.buffer(data)
-
-def compression_mime_type_of_buffer(data):
- mime_type = get_mime_type(data)
- if mime_type in compression_mime_type_handlers:
- return (mime_type, compression_mime_type_handlers[mime_type])
- else:
- raise univention.admin.uexceptions.valueError( "Not a supported compression format: %s" % (mime_type,))
-
-def uncompress_buffer(data):
- try:
- (mime_type, compression_mime_type_handler) = compression_mime_type_of_buffer(data)
- return (mime_type, compression_mime_type_handler(data))
- except univention.admin.uexceptions.valueError:
- return (None, data)
-
-def uncompress_file(filename):
- with open(filename, 'r') as f:
- return uncompress_buffer(f.read())
-
-def image_mime_type_of_buffer(data):
- mime_type = get_mime_type(data)
- if mime_type in ('image/jpeg', 'image/png', 'image/svg+xml', 'application/x-gzip'):
- return mime_type
- else:
- raise univention.admin.uexceptions.valueError( "Not a supported image format: %s" % (mime_type,))
-
-def imagedimensions_of_buffer(data):
- fp = StringIO.StringIO(data)
- im=Image.open(fp)
- return im.size
-
-def imagecategory_of_buffer(data):
- (compression_mime_type, uncompressed_data) = uncompress_buffer(data)
- mime_type = image_mime_type_of_buffer(uncompressed_data)
- if mime_type in ('image/jpeg', 'image/png'):
- return (mime_type, compression_mime_type, "%sx%s" % imagedimensions_of_buffer(uncompressed_data))
- elif mime_type in ('image/svg+xml', 'application/x-gzip'):
- return (mime_type, compression_mime_type, "scalable")
-
-def default_filename_suffix_for_mime_type(mime_type, compression_mime_type):
- if mime_type == 'image/svg+xml':
- if not compression_mime_type:
- return '.svg'
- elif compression_mime_type == 'application/x-gzip':
- return '.svgz'
- elif mime_type == 'image/png':
- return '.png'
- elif mime_type == 'image/jpeg':
- return '.jpg'
- return None
diff --git a/base/univention-lib/shell/umc.sh b/base/univention-lib/shell/umc.sh
deleted file mode 100644
index 6452d31..0000000
--- a/base/univention-lib/shell/umc.sh
+++ /dev/null
@@ -1,121 +0,0 @@
-#!/bin/sh
-# -*- coding: utf-8 -*-
-#
-# Univention Lib
-# shell function for creating UMC operation and acl objects
-#
-# Copyright 2011-2016 Univention GmbH
-#
-# http://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
-# .
-
-
-eval "$(/usr/sbin/univention-config-registry shell ldap/base)"
-
-BIND_ARGS="$@"
-
-umc_frontend_new_hash () {
- # create new timestamps for index.html and debug.html in order to
- # avoid caching problems in browsers
- timestamp=$(date +'%Y%d%m%H%M%S')
- for ifile in index.html debug.html error.html js/umc/login.html; do
- f="/usr/share/univention-management-console-frontend/$ifile"
- [ -w "$f" ] && sed -i 's/\$\(.*\)\$/$'$timestamp'$/' "$f"
- done
-
- # update the symlinks to the js/css directories
- for idir in css js; do
- rm -f "/usr/share/univention-management-console-frontend/${idir}_\$"*\$ || true
- ln -s "$idir" "/usr/share/univention-management-console-frontend/${idir}_\$${timestamp}\$" || true
- done
-
- return 0
-}
-
-umc_init () {
-
- eval "$(/usr/sbin/univention-config-registry shell groups/default/domainadmins groups/default/domainusers)"
-
- # containers
- udm container/cn create $BIND_ARGS --ignore_exists --position "cn=univention,$ldap_base" --set name=UMC || exit $?
- udm container/cn create $BIND_ARGS --ignore_exists --position "cn=policies,$ldap_base" --set name=UMC --set policyPath=1 || exit $?
- udm container/cn create $BIND_ARGS --ignore_exists --position "cn=UMC,cn=univention,$ldap_base" --set name=operations || exit $?
-
- # default admin policy
- udm policies/umc create $BIND_ARGS --ignore_exists --set name=default-umc-all \
- --position "cn=UMC,cn=policies,$ldap_base" || exit $?
-
- # link default admin policy to the group "Domain Admins"
- group_admins="${groups_default_domainadmins:-Domain Admins}"
- udm groups/group modify $BIND_ARGS --ignore_exists --dn "cn=$group_admins,cn=groups,$ldap_base" \
- --policy-reference="cn=default-umc-all,cn=UMC,cn=policies,$ldap_base" || exit $?
-
- # default user policy
- udm policies/umc create $BIND_ARGS --ignore_exists --set name=default-umc-users \
- --position "cn=UMC,cn=policies,$ldap_base" || exit $?
-
- # link default user policy to the group "Domain Users"
- group_users="${groups_default_domainusers:-Domain Users}"
- udm groups/group modify $BIND_ARGS --ignore_exists --dn "cn=$group_users,cn=groups,$ldap_base" \
- --policy-reference="cn=default-umc-users,cn=UMC,cn=policies,$ldap_base" || exit $?
-}
-
-_umc_remove_old () {
- # removes an object and ignores all errors
- name=$1; shift
- module=$1; shift
- container=$1
-
- udm $module remove $BIND_ARGS --dn "cn=$name,$container,$ldap_base" 2>/dev/null || true
-}
-
-umc_operation_create () {
- # example: umc_operation_create "udm" "UDM" "users/user" "udm/*:objectType=users/*"
- name=$1; shift
- description=$1; shift
- flavor=$1; shift
- operations=""
- for oper in "$@"; do
- operations="$operations --append operation=$oper "
- done
- udm settings/umc_operationset create $BIND_ARGS --ignore_exists \
- --position "cn=operations,cn=UMC,cn=univention,$ldap_base" \
- --set name="$name" \
- --set description="$description" \
- --set flavor="$flavor" $operations || exit $?
-}
-
-umc_policy_append () {
- # example: umc_policy_append "default-umc-all" "udm-all" "udm-users"
- policy="$1"; shift
-
- ops=""
- for op in "$@"; do
- ops="$ops --append allow=cn=$op,cn=operations,cn=UMC,cn=univention,$ldap_base "
- done
-
- udm policies/umc modify $BIND_ARGS --ignore_exists \
- --dn "cn=$policy,cn=UMC,cn=policies,$ldap_base" $ops || exit $?
-}
diff --git a/management/univention-management-console/debian/control b/management/univention-management-console/debian/control
index e999998..68cfd92 100644
--- a/management/univention-management-console/debian/control
+++ b/management/univention-management-console/debian/control
@@ -169,3 +169,32 @@ Description: UCS Management Console - Web server
an integrated, directory driven solution for managing
corporate environments. For more information about UCS,
refer to: http://www.univention.de/
+
+Package: python-univention-lib-umc
+Architecture: all
+Depends: ${python:Depends},
+ ${misc:Depends},
+ python-univention-config-registry,
+Provides: ${python:Provides}
+Description: common UMC scripting functions for Python scripts
+ This package contains Python functions used by various
+ components of UCS.
+ .
+ It is part of Univention Corporate Server (UCS), an
+ integrated, directory driven solution for managing
+ corporate environments. For more information about UCS,
+ refer to: http://www.univention.de/
+
+Package: shell-univention-lib
+Architecture: all
+Depends: ${misc:Depends},
+ python-univention-config-registry,
+ python-univention-lib-umc,
+Description: common UMC scripting functions for shell scripts
+ This package contains shell functions used by various
+ components of UCS.
+ .
+ It is part of Univention Corporate Server (UCS), an
+ integrated, directory driven solution for managing
+ corporate environments. For more information about UCS,
+ refer to: http://www.univention.de/
diff --git a/management/univention-management-console/lib/python/umc_connection.py b/management/univention-management-console/lib/python/umc_connection.py
new file mode 100644
index 0000000..65c6d05
--- /dev/null
+++ b/management/univention-management-console/lib/python/umc_connection.py
@@ -0,0 +1,148 @@
+#!/usr/bin/python2.7
+# -*- coding: utf-8 -*-
+#
+# Univention Common Python Library
+# Connections to remote UMC Servers
+#
+# Copyright 2013-2016 Univention GmbH
+#
+# http://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
+# .
+
+from httplib import HTTPSConnection, HTTPException
+from json import loads, dumps
+from socket import error as SocketError
+
+from univention.config_registry import ConfigRegistry
+ucr = ConfigRegistry()
+ucr.load()
+
+
+class UMCConnection(object):
+
+ def __init__(self, host, username=None, password=None, error_handler=None):
+ self._host = host
+ self._headers = {
+ 'Content-Type': 'application/json; charset=UTF-8',
+ 'Accept': 'application/json; q=1, text/html; q=0.5; */*; q=0.1',
+ 'X-Requested-With': 'XMLHttpRequest',
+ }
+ self._error_handler=error_handler
+ if username is not None:
+ self.auth(username, password)
+
+ def get_connection(self):
+ '''Creates a new HTTPSConnection to the host'''
+ # once keep-alive is over, the socket closes
+ # so create a new connection on every request
+ return HTTPSConnection(self._host)
+
+ @classmethod
+ def get_machine_connection(cls, error_handler=None):
+ '''Creates a connection with the credentials of the local host
+ to the DC Master'''
+ username = '%s$' % ucr.get('hostname')
+ password = ''
+ try:
+ with open('/etc/machine.secret') as machine_file:
+ password = machine_file.readline().strip()
+ except (OSError, IOError) as e:
+ if error_handler:
+ error_handler('Could not read /etc/machine.secret: %s' % e)
+ try:
+ connection = cls(ucr.get('ldap/master'))
+ connection.auth(username, password)
+ return connection
+ except (HTTPException, SocketError) as e:
+ if error_handler:
+ error_handler('Could not connect to UMC on %s: %s' % (ucr.get('ldap/master'), e))
+ return None
+
+ def auth(self, username, password, auth_type=None):
+ '''Tries to authenticate against the host and preserves the
+ cookie. Has to be done only once (but keep in mind that the
+ session probably expires after 10 minutes of inactivity)'''
+ data = self.build_data({'username' : username, 'password' : password, 'auth_type': auth_type})
+ con = self.get_connection()
+ try:
+ con.request('POST', '/umcp/auth', data, headers=self._headers)
+ except Exception as e:
+ # probably unreachable
+ if self._error_handler:
+ self._error_handler(str(e))
+ error_message = '%s: Authentication failed while contacting: %s' % (self._host, e)
+ raise HTTPException(error_message)
+ else:
+ try:
+ response = con.getresponse()
+ cookie = response.getheader('set-cookie')
+ if cookie is None:
+ raise ValueError('No cookie')
+ self._headers['Cookie'] = cookie # FIXME: transform Set-Cookie to Cookie
+ except Exception as e:
+ if self._error_handler:
+ self._error_handler(str(e))
+ error_message = '%s: Authentication failed: %s' % (self._host, response.read())
+ raise HTTPException(error_message)
+
+ def build_data(self, data, flavor=None):
+ '''Returns a dictionary as expected by the UMC Server'''
+ data = {'options' : data}
+ if flavor:
+ data['flavor'] = flavor
+ return dumps(data)
+
+ def request(self, url, data=None, flavor=None, command='command'):
+ '''Sends a request and returns the data from the response. url
+ as in the XML file of that UMC module.
+ command may be anything that UMCP understands, especially:
+ * command (default)
+ * get (and url could be 'ucr' then)
+ * set (and url would be '' and data could be {'locale':'de_DE'})
+ * upload (url could be 'udm/license/import')
+ '''
+ if data is None:
+ data = {}
+ data = self.build_data(data, flavor)
+ con = self.get_connection()
+ umcp_command = '/umcp/%s' % command
+ if url:
+ umcp_command = '%s/%s' % (umcp_command, url)
+ con.request('POST', umcp_command, data, headers=self._headers)
+ response = con.getresponse()
+ if response.status != 200:
+ error_message = '%s on %s (%s): %s' % (response.status, self._host, url, response.read())
+ if response.status == 403:
+ # 403 is either command is unknown
+ # or command is known but forbidden
+ if self._error_handler:
+ self._error_handler(error_message)
+ raise NotImplementedError('command forbidden: %s' % url)
+ raise HTTPException(error_message)
+ content = response.read()
+ content = loads(content) # FIXME: inspect Content-Type response header
+ if isinstance(content, dict):
+ return content.get('result', content)
+ return content
diff --git a/management/univention-management-console/lib/python/umc_module.py b/management/univention-management-console/lib/python/umc_module.py
new file mode 100644
index 0000000..e57dd1a
--- /dev/null
+++ b/management/univention-management-console/lib/python/umc_module.py
@@ -0,0 +1,73 @@
+import univention.admin.uexceptions
+import bz2
+import zlib
+from PIL import Image
+import StringIO
+import magic
+MIME_TYPE = magic.open(magic.MAGIC_MIME_TYPE)
+MIME_TYPE.load()
+MIME_DESCRIPTION = magic.open(magic.MAGIC_NONE)
+MIME_DESCRIPTION.load()
+
+UMC_ICON_BASEDIR = "/usr/share/univention-management-console-frontend/js/dijit/themes/umc/icons"
+
+compression_mime_type_handlers = {
+ "application/x-gzip": lambda x: zlib.decompress(x, 16+zlib.MAX_WBITS),
+ "application/x-bzip2": bz2.decompress
+}
+
+def get_mime_type(data):
+ return MIME_TYPE.buffer(data)
+
+def get_mime_description(data):
+ return MIME_DESCRIPTION.buffer(data)
+
+def compression_mime_type_of_buffer(data):
+ mime_type = get_mime_type(data)
+ if mime_type in compression_mime_type_handlers:
+ return (mime_type, compression_mime_type_handlers[mime_type])
+ else:
+ raise univention.admin.uexceptions.valueError( "Not a supported compression format: %s" % (mime_type,))
+
+def uncompress_buffer(data):
+ try:
+ (mime_type, compression_mime_type_handler) = compression_mime_type_of_buffer(data)
+ return (mime_type, compression_mime_type_handler(data))
+ except univention.admin.uexceptions.valueError:
+ return (None, data)
+
+def uncompress_file(filename):
+ with open(filename, 'r') as f:
+ return uncompress_buffer(f.read())
+
+def image_mime_type_of_buffer(data):
+ mime_type = get_mime_type(data)
+ if mime_type in ('image/jpeg', 'image/png', 'image/svg+xml', 'application/x-gzip'):
+ return mime_type
+ else:
+ raise univention.admin.uexceptions.valueError( "Not a supported image format: %s" % (mime_type,))
+
+def imagedimensions_of_buffer(data):
+ fp = StringIO.StringIO(data)
+ im=Image.open(fp)
+ return im.size
+
+def imagecategory_of_buffer(data):
+ (compression_mime_type, uncompressed_data) = uncompress_buffer(data)
+ mime_type = image_mime_type_of_buffer(uncompressed_data)
+ if mime_type in ('image/jpeg', 'image/png'):
+ return (mime_type, compression_mime_type, "%sx%s" % imagedimensions_of_buffer(uncompressed_data))
+ elif mime_type in ('image/svg+xml', 'application/x-gzip'):
+ return (mime_type, compression_mime_type, "scalable")
+
+def default_filename_suffix_for_mime_type(mime_type, compression_mime_type):
+ if mime_type == 'image/svg+xml':
+ if not compression_mime_type:
+ return '.svg'
+ elif compression_mime_type == 'application/x-gzip':
+ return '.svgz'
+ elif mime_type == 'image/png':
+ return '.png'
+ elif mime_type == 'image/jpeg':
+ return '.jpg'
+ return None
diff --git a/management/univention-management-console/lib/shell/umc.sh b/management/univention-management-console/lib/shell/umc.sh
new file mode 100644
index 0000000..6452d31
--- /dev/null
+++ b/management/univention-management-console/lib/shell/umc.sh
@@ -0,0 +1,121 @@
+#!/bin/sh
+# -*- coding: utf-8 -*-
+#
+# Univention Lib
+# shell function for creating UMC operation and acl objects
+#
+# Copyright 2011-2016 Univention GmbH
+#
+# http://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
+# .
+
+
+eval "$(/usr/sbin/univention-config-registry shell ldap/base)"
+
+BIND_ARGS="$@"
+
+umc_frontend_new_hash () {
+ # create new timestamps for index.html and debug.html in order to
+ # avoid caching problems in browsers
+ timestamp=$(date +'%Y%d%m%H%M%S')
+ for ifile in index.html debug.html error.html js/umc/login.html; do
+ f="/usr/share/univention-management-console-frontend/$ifile"
+ [ -w "$f" ] && sed -i 's/\$\(.*\)\$/$'$timestamp'$/' "$f"
+ done
+
+ # update the symlinks to the js/css directories
+ for idir in css js; do
+ rm -f "/usr/share/univention-management-console-frontend/${idir}_\$"*\$ || true
+ ln -s "$idir" "/usr/share/univention-management-console-frontend/${idir}_\$${timestamp}\$" || true
+ done
+
+ return 0
+}
+
+umc_init () {
+
+ eval "$(/usr/sbin/univention-config-registry shell groups/default/domainadmins groups/default/domainusers)"
+
+ # containers
+ udm container/cn create $BIND_ARGS --ignore_exists --position "cn=univention,$ldap_base" --set name=UMC || exit $?
+ udm container/cn create $BIND_ARGS --ignore_exists --position "cn=policies,$ldap_base" --set name=UMC --set policyPath=1 || exit $?
+ udm container/cn create $BIND_ARGS --ignore_exists --position "cn=UMC,cn=univention,$ldap_base" --set name=operations || exit $?
+
+ # default admin policy
+ udm policies/umc create $BIND_ARGS --ignore_exists --set name=default-umc-all \
+ --position "cn=UMC,cn=policies,$ldap_base" || exit $?
+
+ # link default admin policy to the group "Domain Admins"
+ group_admins="${groups_default_domainadmins:-Domain Admins}"
+ udm groups/group modify $BIND_ARGS --ignore_exists --dn "cn=$group_admins,cn=groups,$ldap_base" \
+ --policy-reference="cn=default-umc-all,cn=UMC,cn=policies,$ldap_base" || exit $?
+
+ # default user policy
+ udm policies/umc create $BIND_ARGS --ignore_exists --set name=default-umc-users \
+ --position "cn=UMC,cn=policies,$ldap_base" || exit $?
+
+ # link default user policy to the group "Domain Users"
+ group_users="${groups_default_domainusers:-Domain Users}"
+ udm groups/group modify $BIND_ARGS --ignore_exists --dn "cn=$group_users,cn=groups,$ldap_base" \
+ --policy-reference="cn=default-umc-users,cn=UMC,cn=policies,$ldap_base" || exit $?
+}
+
+_umc_remove_old () {
+ # removes an object and ignores all errors
+ name=$1; shift
+ module=$1; shift
+ container=$1
+
+ udm $module remove $BIND_ARGS --dn "cn=$name,$container,$ldap_base" 2>/dev/null || true
+}
+
+umc_operation_create () {
+ # example: umc_operation_create "udm" "UDM" "users/user" "udm/*:objectType=users/*"
+ name=$1; shift
+ description=$1; shift
+ flavor=$1; shift
+ operations=""
+ for oper in "$@"; do
+ operations="$operations --append operation=$oper "
+ done
+ udm settings/umc_operationset create $BIND_ARGS --ignore_exists \
+ --position "cn=operations,cn=UMC,cn=univention,$ldap_base" \
+ --set name="$name" \
+ --set description="$description" \
+ --set flavor="$flavor" $operations || exit $?
+}
+
+umc_policy_append () {
+ # example: umc_policy_append "default-umc-all" "udm-all" "udm-users"
+ policy="$1"; shift
+
+ ops=""
+ for op in "$@"; do
+ ops="$ops --append allow=cn=$op,cn=operations,cn=UMC,cn=univention,$ldap_base "
+ done
+
+ udm policies/umc modify $BIND_ARGS --ignore_exists \
+ --dn "cn=$policy,cn=UMC,cn=policies,$ldap_base" $ops || exit $?
+}