├── .gitignore ├── Readme.md ├── createreleases ├── Readme.md └── mirror_kolab_development.py ├── cypress.json ├── cypress └── integration │ └── UserAllAroundCheck.js ├── dply ├── Readme.md ├── dply.sh └── reinstallKolab.sh ├── kolab ├── Dockerfile ├── addDomain.sh ├── disableCanonification.sh ├── disableGuam.sh ├── disableSpamFilter.sh ├── imapproxy │ ├── imapproxy.conf │ ├── nginx.conf │ ├── stunnel │ └── stunnel.conf ├── initHttpTunnel.sh ├── initIMAPProxy.sh ├── initMailCatchall.sh ├── initMailForward.sh ├── initMultiDomain.sh ├── initRoundcubePlugins.sh ├── initSSL.sh ├── initSetupKolabPatches.sh ├── initSleepTimesForTest.sh ├── initTBitsCustomizationsDE.sh ├── initTBitsISP.sh ├── initTBitsUserTypes.php ├── key │ └── devel@lists.kolab.org.asc ├── lib.sh ├── patches │ ├── 99tbits.ldif │ ├── allowPrimaryEmailAddressFromDomain.patch │ ├── canonification_via_uid_pykolab.patch │ ├── canonification_via_uid_roundcube.patch │ ├── canonification_via_uid_wap.patch │ ├── cyrus_canonification.patch │ ├── cyrus_canonification_multiple_domains.patch │ ├── cyrus_filter_kolab_mailboxes.patch │ ├── disableSpamFilter.patch │ ├── disableSpamFilter2.patch │ ├── domainAdminDefaultQuota.patch │ ├── domainAdminMaxAccounts.patch │ ├── domainquotaBug2046.patch │ ├── dont_generate_attribs_when_editing.patch │ ├── fixPykolabIMAPKeepAlive.patch │ ├── intranetToken-wap.patch │ ├── kolab_lam_invalid_mailbox_name.patch │ ├── lastLoginTBitsAttribute-pykolab.patch │ ├── lastLoginTBitsAttribute-wap.patch │ ├── listUsersLastLoginQuotaUsage.patch │ ├── logLoginData.patch │ ├── managesieveWithMessagelabel.patch │ ├── onlyAllowKolabUsersToAuthViaSasl.patch │ ├── optional_disable_addressbook_export.patch │ ├── patchMultiDomainAdminsBug2018.patch │ ├── pykolab_do_not_rename_existing_mailbox_T3315.patch │ ├── pykolab_wap_client_unverified_context_localhost.patch │ ├── quotaused_wap.patch │ ├── roundcubeStorageMariadbBug4883.patch │ ├── roundcube_calendar_etc_timezone_T2666.patch │ ├── roundcube_kolab_auth_canonification.patch │ ├── setupKolabSleepDirSrv.patch │ ├── sleepTimeDomainTests.patch │ ├── validateAliasDomainPostfixVirtualFileBug2658.patch │ ├── wap_api_listuserswithhash.patch │ └── wap_disallow_users.patch ├── reinstall.sh ├── reinstallCentOS.sh └── reinstallDebianUbuntu.sh ├── package-lock.json └── pySeleniumTests ├── Readme.md ├── configureKolabUserMailhost.py ├── helperKolabWAP.py ├── runTests.sh ├── testAutoCreateFolders.py ├── testCreateUserAndEditSelf.py ├── testDomainAdmin.py ├── testDomainAdminDefaultQuota.py ├── testDomainAdminMaxAccounts.py ├── testDomainAdminOverallQuota.py ├── testEmailCatchAll.py ├── testEmailCatchAllAcrossDomains.py ├── testEmailForwarding.py ├── testEmailSendAndReceive.py ├── testEmailSharedFolders.py ├── testLastLogin.py ├── testListUsersQuota.py ├── testRoundcubeChangePassword.py └── testUIDAcrossDomains.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | pySeleniumTests/ghostdriver.log 3 | pySeleniumTests/geckodriver.log 4 | kolab/key 5 | kolab/keys 6 | cypress/screenshots 7 | cypress/fixtures 8 | cypress/plugins 9 | cypress/support 10 | node_modules 11 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | Attention 2 | ========= 3 | 4 | Please use the scripts only if you understand them. We don't give any guarantuee that they will work or will destroy your data. 5 | 6 | 7 | Contributing 8 | ============ 9 | 10 | You are welcome to provide Pull requests on Github, if you spot a problem or want to suggest an improvement! 11 | 12 | 13 | Layout 14 | ====== 15 | 16 | We have organised the scripts according to the releases. 17 | Please have a look in the branches. 18 | So if you want to work with Kolab 16, go to https://github.com/TBits/KolabScripts/tree/Kolab16 19 | 20 | For more details, please visit the wiki at https://github.com/tbits/kolabscripts/wiki 21 | 22 | 23 | Tests with Cypress 24 | ================== 25 | 26 | prepare installation: 27 | 28 | npm install 29 | 30 | Test with a GUI: 31 | 32 | LANG=en CYPRESS_baseUrl=https://localhost ./node_modules/.bin/cypress open 33 | 34 | Test on the command line: 35 | 36 | LANG=en CYPRESS_baseUrl=https://localhost ./node_modules/.bin/cypress run --config video=false 37 | 38 | -------------------------------------------------------------------------------- /createreleases/Readme.md: -------------------------------------------------------------------------------- 1 | Build Instructions 2 | ====== 3 | 4 | This helps to build regular releases based on Kolab Development. The version scheme should contain the year and the month of the release, eg. Kolab-2016.02. This release can be done with a release candidate before the final release. 5 | 6 | The script will download the source rpms from the Kolab Systems OBS, from the location http://obs.kolabsys.com/repositories/Kolab:/Development/CentOS_7/src/ 7 | 8 | It will process the source rpms, and adjust the spec files to modify the version of the packages. 9 | 10 | * we want to see in the rpm package name the git version of the release. 11 | * we want to see the Kolab release in the package name. 12 | 13 | The script will push the package definition to Github, so that I can build the CentOS6 packages on LBS. 14 | 15 | The script will upload the source rpms to FedoraPeople.org: https://tpokorra.fedorapeople.org/kolab/kolab-/. sftp will use my private key stored at ~/.ssh/id_rsa 16 | 17 | Then the script will install the source rpms, and check the spec files to determine the order in which the packages need to be built. Then it will print the packages that can be built in parallel, and which sets of packages must be built in that order. 18 | 19 | If somebody else is using this script, you need to change the urls and usernames at the top of the script. 20 | 21 | Then run: 22 | 23 | ./mirror_kolab_development.py 2015.2 RC1 24 | ./mirror_kolab_development.py 2015.2 final 25 | 26 | Which will show which packages should be built together. 27 | 28 | Paste these links at the copr build page: https://copr.fedoraproject.org/coprs/tpokorra/Kolab-3.5-Preparation/add_build/ 29 | 30 | And wait for the builds to finish, and then do the next block of packages. 31 | 32 | Installing Kolab from the copr repositories 33 | == 34 | 35 | Now you can install Kolab from the copr repositories. 36 | 37 | For CentOS7: 38 | 39 | yum install epel-release yum-plugin-priorities 40 | cd /etc/yum.repos.d/ 41 | wget https://copr.fedoraproject.org/coprs/tpokorra/Kolab-3.5/repo/epel-7/tpokorra-Kolab-3.5-Preparation-epel-7.repo -O Kolab-3.5-Preparation.repo 42 | 43 | # Make sure that the packages from the Kolab repositories have a higher priority than eg. the Epel packages: 44 | for f in /etc/yum.repos.d/Kolab*.repo; do sed -i "s#enabled=1#enabled=1\npriority=1#g" $f; done 45 | 46 | yum install kolab 47 | 48 | # now follow the instructions at https://docs.kolab.org/installation-guide/setup-kolab.html#install-setup-kolab 49 | -------------------------------------------------------------------------------- /createreleases/mirror_kolab_development.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import os.path 3 | import sys 4 | from collections import deque 5 | import urllib.request 6 | import re 7 | 8 | if len(sys.argv) != 3: 9 | print("Please specify which Kolab version you want to create eg. 2016.2 RC1 or 2016.2 final") 10 | sys.exit(-1) 11 | release=sys.argv[1] 12 | releasestate=sys.argv[2] 13 | rpmbuildpath="/root/rpmbuild" 14 | obsurl="http://obs.kolabsys.com/repositories/Kolab:/Development/CentOS_7/src" 15 | fedorapeoplepath="kolab/kolab-"+release+"/"+releasestate 16 | fedorapeopleurl="tpokorra@fedorapeople.org:public_html" 17 | pkgurl="https://tpokorra.fedorapeople.org/"+fedorapeoplepath 18 | srcrpmspath="/root/obs/kolab-development" 19 | modifiedsrcrpmspath="/root/obs/kolab-development" 20 | Debugging=False 21 | 22 | includePackages=[ 23 | # kolab packages 24 | "chwala", "iRony", "kolab*", "libcalendaring", "libkolab*", "pykolab", 25 | "roundcubemail-plugins-kolab", "roundcubemail-skin-chameleon", 26 | # additional packages 27 | "cyrus-imapd", "roundcubemail", "roundcubemail-plugin-*", 28 | # needed by roundcubemail 29 | "php-Net-LDAP3", "php-pear-Net-LDAP2", 30 | # needed by pykolab 31 | "python-icalendar", "python-sievelib", 32 | # needed by kolab-webadmin 33 | "mozldap", 34 | # needed by iRony 35 | "php-sabre-*"] 36 | 37 | def GetDependanciesAndProvides(name): 38 | specfile=rpmbuildpath + "/SPECS/" + name + ".spec" 39 | builddepends=[] 40 | provides={} 41 | if not os.path.isfile(specfile): 42 | print("cannot find " + specfile) 43 | else: 44 | globals = {} 45 | for line in open(specfile): 46 | for glob in globals: 47 | line=line.replace("%{"+glob+"}", globals[glob]) 48 | if line.lower().startswith("%global "): 49 | glob = line.strip().split() 50 | globals[glob[1]] = glob[2] 51 | if line.lower().startswith("buildrequires: "): 52 | if line.count(",") > 0: 53 | packagesWithVersions=line[len("BuildRequires: "):].split(",") 54 | else: 55 | packagesWithVersions=line[len("BuildRequires: "):].split() 56 | ignoreNext=False 57 | for word in packagesWithVersions: 58 | if not ignoreNext: 59 | # filter >= 3.0, only use package names 60 | if word[0] == '>' or word[0] == '<' or word[0] == '=': 61 | ignoreNext=True 62 | else: 63 | builddepends.append(word.strip()) 64 | else: 65 | ignoreNext=False 66 | 67 | recentpackagename=name 68 | for line in open(specfile): 69 | if line.lower().startswith("name:"): 70 | name = line[len("name:"):].strip() 71 | recentpackagename=name 72 | provides[name] = [] 73 | elif line.lower().startswith("%package -n"): 74 | recentpackagename=line[len("%package -n"):].strip() 75 | provides[recentpackagename] = [] 76 | elif line.lower().startswith("%package"): 77 | recentpackagename=name + "-" + line[len("%package"):].strip() 78 | provides[recentpackagename] = [] 79 | elif line.lower().startswith("requires:"): 80 | r = line[len("requires:"):].strip().replace("(", "-").replace(")", "") 81 | provides[recentpackagename].append(r.split()[0]) 82 | 83 | return (builddepends, provides) 84 | 85 | def CalculatePackageOrder(packages): 86 | unsorted={} 87 | builddepends={} 88 | depends={} 89 | provides={} 90 | for package in packages: 91 | (builddepends[package],provides[package]) = GetDependanciesAndProvides(package) 92 | for p in provides[package]: 93 | unsorted[p] = 1 94 | depends[p] = provides[package][p] 95 | if not package in unsorted: 96 | unsorted[package] = 1 97 | # useful for debugging: 98 | if Debugging: 99 | print( package + " builddepends on: ") 100 | for p in builddepends[package]: 101 | print(" " + p) 102 | print( package + " provides: ") 103 | for p in provides[package]: 104 | print(" " + p + " which depends on:") 105 | for d in depends[p]: 106 | print(" " + d) 107 | 108 | result = deque() 109 | while len(unsorted) > 0: 110 | nextPackages = [] 111 | for package in unsorted: 112 | if package in packages: 113 | missingRequirement=False 114 | # check that this package does not require a package that is in unsorted 115 | for dep in builddepends[package]: 116 | if dep in unsorted: 117 | missingRequirement=True 118 | if dep in depends: 119 | for dep2 in depends[dep]: 120 | if dep2 in unsorted: 121 | missingRequirement=True 122 | if not missingRequirement: 123 | nextPackages.append(package) 124 | added=True 125 | if nextPackages.count == 0: 126 | # problem: circular dependancy 127 | print ("circular dependancy, remaining packages: ") 128 | for p in unsorted: 129 | print(p) 130 | return None 131 | result.append(nextPackages) 132 | for pkg in nextPackages: 133 | for p in provides[pkg]: 134 | if p in unsorted: 135 | del unsorted[p] 136 | for pkg in nextPackages: 137 | if pkg in unsorted: 138 | del unsorted[pkg] 139 | 140 | return result 141 | 142 | def getPackages(): 143 | packages=[] 144 | for file in os.listdir(rpmbuildpath+"/SPECS"): 145 | if file.endswith(".spec"): 146 | packages.append(file[:-5]) 147 | return packages 148 | 149 | def getSrcRpmFiles(packages): 150 | result={} 151 | 152 | # parse name from spec file 153 | srcrpmnames={} 154 | for pkg in packages: 155 | srcrpmnames[pkg] = pkg 156 | globals = {} 157 | for line in open(rpmbuildpath+"/SPECS/" + pkg + ".spec"): 158 | for glob in globals: 159 | line=line.replace("%{"+glob+"}", globals[glob]) 160 | if line.lower().startswith("%global "): 161 | glob = line.strip().split() 162 | globals[glob[1]] = glob[2] 163 | if line.startswith("Name: "): 164 | srcrpmnames[pkg] = line[6:].strip() 165 | 166 | for file in os.listdir(srcrpmspath): 167 | if file.endswith(".src.rpm"): 168 | bestfit=None 169 | bestfitCount=0 170 | for pkg in packages: 171 | pkgsrcname = srcrpmnames[pkg] 172 | if file.startswith(pkgsrcname): 173 | if len(pkgsrcname) > bestfitCount: 174 | bestfitCount=len(pkgsrcname) 175 | bestfit=pkg 176 | if bestfit is not None: 177 | result[bestfit] = file 178 | return result 179 | 180 | def downloadSrcRpms(): 181 | if os.path.isdir(srcrpmspath): 182 | print("not downloading the src.rpms again. please delete the path " + srcrpmspath + " if you want a fresh download") 183 | return 184 | response = urllib.request.urlopen(obsurl) 185 | os.makedirs(srcrpmspath) 186 | html = response.read().decode('utf-8') 187 | for line in html.split('\n'): 188 | if "src.rpm" in line: 189 | m = re.search(']+>', line) 190 | m2 = re.search('"[^\"]+"', m.group(0)) 191 | srcrpm=m2.group(0).strip('"') 192 | ignore=True 193 | for pkg in includePackages: 194 | if srcrpm.startswith(pkg.replace('*','')): 195 | ignore=False 196 | if not ignore: 197 | os.system("wget " + obsurl + "/" + srcrpm + " -O " + srcrpmspath + "/" + srcrpm) 198 | 199 | def uploadSrcRpms(): 200 | os.system("echo 'mkdir "+fedorapeoplepath+"' | sftp " + fedorapeopleurl) 201 | os.system("cd "+modifiedsrcrpmspath+" && echo 'put *.src.rpm' | sftp " + fedorapeopleurl + "/" + fedorapeoplepath) 202 | 203 | def installSrcRpms(): 204 | # need a clean rpmbuild directory 205 | if os.path.isdir(rpmbuildpath): 206 | if os.path.isdir(rpmbuildpath + ".bak"): 207 | print("Error: cannot rename " + rpmbuildpath + " because " + rpmbuildpath + ".bak already exist") 208 | sys.exit(-1) 209 | os.rename(rpmbuildpath, rpmbuildpath + ".bak") 210 | for file in os.listdir(srcrpmspath): 211 | if file.endswith(".src.rpm"): 212 | os.system("rpm -i " + srcrpmspath + "/" + file) 213 | 214 | def printPackages(orderedpackages): 215 | for pkgs in orderedpackages: 216 | print() 217 | print("build together: ") 218 | for pkg in pkgs: 219 | if pkg in srcrpmfiles: 220 | print(pkgurl + "/" + srcrpmfiles[pkg]) 221 | else: 222 | print(" " + pkg) 223 | 224 | #downloadSrcRpms() 225 | #installSrcRpms() 226 | #uploadSrcRpms() 227 | packages=getPackages() 228 | srcrpmfiles=getSrcRpmFiles(packages) 229 | orderedpackages=CalculatePackageOrder(packages) 230 | printPackages(orderedpackages) 231 | 232 | -------------------------------------------------------------------------------- /cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultCommandTimeout": 10000, 3 | "video": false 4 | } 5 | -------------------------------------------------------------------------------- /cypress/integration/UserAllAroundCheck.js: -------------------------------------------------------------------------------- 1 | function login(u, p) { 2 | cy.visit("/kolab-webadmin") 3 | cy.get('#login_name').clear().type(u) 4 | cy.get('#login_pass').clear().type(p) 5 | cy.get('#login_submit').click() 6 | } 7 | 8 | describe('create testerino', function() { 9 | it('login and out', function() { 10 | login("cn=Directory Manager", "test") 11 | cy.get('#topmenu .logout').should("be.visible").click() 12 | }) 13 | it('create user', function() { 14 | login("cn=Directory Manager", "test") 15 | cy.wait(500) 16 | cy.get("#main .user").click() 17 | cy.wait(500) 18 | cy.get("#user-form [name=givenname]").clear().type("Max") 19 | cy.get("#user-form [name=sn]").clear().type("Musterman") 20 | cy.get("#user-form [name=initials]").clear().type("MM") 21 | cy.get("#user-form [name=o]").clear().type("Max Musterman's Farb Tapeten Königreich") 22 | cy.get("#user-form [name=title]").clear().type("Tapetenmeister") 23 | 24 | cy.get(".nav-tabs .nav-item").eq(2).find("a").click() 25 | cy.wait(500) 26 | cy.get("#user-form [name=userpassword]").clear().type("testtest") 27 | cy.get("#user-form [name=userpassword2]").clear().type("testtest") 28 | cy.get("#user-form input.submit").click() 29 | 30 | }) 31 | it('login as user and change stuff', function() { 32 | login("musterman", "testtest") 33 | cy.wait(500) 34 | cy.get("#main .user").click() 35 | 36 | cy.get("#userlist .selectable").first().click() 37 | cy.wait(2500) 38 | cy.get("#user-form [name=initials]").clear().type("MMMMMMMM") 39 | cy.get("#user-form [name=o]").clear().type("MAXimal Ideenlose Org.") 40 | cy.get("#user-form [name=title]").clear().type("Nothing, just nothing") 41 | cy.get("#user-form input.submit").click() 42 | }) 43 | it('login again and check infos', function() { 44 | login("musterman", "testtest") 45 | cy.wait(500) 46 | cy.get("#main .user").click() 47 | cy.get("#userlist .selectable").first().click() 48 | cy.wait(500) 49 | cy.get("#user-form [name=initials]").should('has.value', "MMMMMMMM") 50 | cy.get("#user-form [name=o]").should("has.value","MAXimal Ideenlose Org.") 51 | cy.get("#user-form [name=title]").should("has.value","Nothing, just nothing") 52 | cy.get('#topmenu .logout').should("be.visible").click() 53 | 54 | }) 55 | it('change password', function() { 56 | login("musterman", "testtest") 57 | cy.wait(500) 58 | cy.get("#main .user").click() 59 | cy.get("#userlist .selectable").first().click() 60 | cy.wait(500) 61 | cy.get(".nav-tabs .nav-item").eq(2).find("a").click() 62 | cy.wait(500) 63 | cy.get("#user-form [name=userpassword]").clear().type("testtesttest") 64 | cy.get("#user-form [name=userpassword2]").clear().type("testtesttest") 65 | cy.get("#user-form input.submit").click() 66 | }) 67 | it('login with new password', function() { 68 | login("musterman", "testtesttest") 69 | cy.get('#topmenu .logout').should("be.visible").click() 70 | }) 71 | it('delete test user', function() { 72 | login("cn=Directory Manager", "test") 73 | cy.wait(500) 74 | cy.get("#main .user").click() 75 | cy.get("#userlist .selectable").first().click() 76 | cy.wait(2500) 77 | cy.get("#user-form .formbuttons input[onclick*=delete]").click() 78 | }) 79 | }) 80 | -------------------------------------------------------------------------------- /dply/Readme.md: -------------------------------------------------------------------------------- 1 | Dply 2 | === 3 | 4 | This service at https://dply.co/ is currently in Beta stage. You can specify a script that should be run when a server on DigitalOcean is started. The first two hours are for free. 5 | 6 | Dply Button 7 | === 8 | 9 | The script that we insert at https://dply.co/button is maintained in this directory: [dply.sh](dply.sh) 10 | 11 | 12 | Kolab on Dply 13 | === 14 | 15 | see also my blog post: http://www.pokorra.de/2016/12/installing-kolab-16-for-testing-on-dply-for-free-for-2-hours/ 16 | -------------------------------------------------------------------------------- /dply/dply.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | swapsize="1GB" 4 | branch="Kolab16" 5 | # recommended: use another password than test for user: cn=Directory Manager 6 | pwd="test" 7 | 8 | # add swap space to deal with small amount of RAM 9 | fallocate -l $swapsize /swapfile1; 10 | mkswap /swapfile1 11 | swapon /swapfile1 12 | echo "/swapfile1 swap swap defaults 0 0" >> /etc/fstab 13 | 14 | yum install -y wget 15 | cd /root 16 | wget https://raw.githubusercontent.com/TBits/KolabScripts/$branch/dply/reinstallKolab.sh -O dply$branch.sh 17 | chmod a+x dply$branch.sh 18 | sed -i "s#KolabWinterfell#$branch#g" dply$branch.sh 19 | 20 | # you can rerun this script if you want to reinstall Kolab. 21 | ./dply$branch.sh $pwd 22 | 23 | # next steps: 24 | # http://your.ip/kolab-webadmin, login with user: cn=Directory Manager, password: as defined at the top of this script, default: test 25 | # http://your.ip/roundcubemail 26 | -------------------------------------------------------------------------------- /dply/reinstallKolab.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -z "$1" ]; then 4 | pwd="test" 5 | else 6 | pwd=$1 7 | fi 8 | 9 | if [ -z "$2" ]; then 10 | branch="KolabWinterfell" 11 | else 12 | branch=$1 13 | fi 14 | 15 | # we need a fully qualified domain name 16 | hostnamectl set-hostname $branch.demo.example.org 17 | 18 | yum install -y wget which bzip2 mailx selinux-policy-targeted 19 | # disable SELinux 20 | sed -i 's/enforcing/permissive/g' /etc/selinux/config 21 | setenforce 0 22 | 23 | wget -O $branch.tar.gz https://github.com/TBits/KolabScripts/archive/$branch.tar.gz 24 | tar xzf $branch.tar.gz 25 | cd KolabScripts-$branch/kolab 26 | # to make Kolab run on 512 MB of RAM on dply.co, disable Amavis and ClamAV 27 | export WITHOUTSPAMFILTER=1 28 | echo "y" | ./reinstall.sh || exit 1 29 | ./initSetupKolabPatches.sh || exit 1 30 | 31 | setup-kolab --default --mysqlserver=new --timezone=Europe/Berlin --directory-manager-pwd=$pwd || exit 1 32 | 33 | # is guam installed at all? 34 | if [[ "`rpm -qa | grep guam`" == "" ]] 35 | then 36 | # make sure that cyrus is listening on the correct ports 37 | ./disableGuam.sh 38 | fi 39 | 40 | # next steps: 41 | # http://your.ip/kolab-webadmin, login with user: cn=Directory Manager, password: as passed to this script, default: test 42 | # http://your.ip/roundcubemail 43 | -------------------------------------------------------------------------------- /kolab/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM centos:7 2 | 3 | # packages should be installed with docs 4 | RUN sed -i -e "s/tsflags=nodocs/#tsflags=nodocs/g" /etc/yum.conf 5 | 6 | ENV container docker 7 | RUN yum -y update; yum clean all 8 | 9 | RUN yum -y install selinux-policy passwd vim tar wget && yum clean all 10 | 11 | # set the initial root password so that you can login with docker attach 12 | RUN echo root:root | chpasswd 13 | 14 | # disable SELINUX 15 | RUN sed -i "s/SELINUX=enforcing/SELINUX=disabled/g" /etc/selinux/config 16 | 17 | WORKDIR /root 18 | RUN wget -O kolabscripts.tar.gz https://github.com/TBits/KolabScripts/archive/Kolab16.tar.gz; tar xzf kolabscripts.tar.gz; rm -f kolabscripts.tar.gz 19 | WORKDIR /root/KolabScripts-Kolab16/kolab 20 | # we want to install the kolab packages in a separate step 21 | RUN sed -i -e "s/yum -y install kolab/#yum -y install kolab/" reinstallCentOS.sh 22 | RUN echo "y" | ./reinstallCentOS.sh CentOS_7 23 | 24 | # TODO: modify the next command to rebuild the package. eg echo "packages from 2016-03-22" && ... 25 | RUN yum -y install kolab kolab-freebusy && yum clean all 26 | 27 | # prepare for setup kolab 28 | RUN sed -i -e "s/systemctl start guam/#systemctl start guam/g" initSetupKolabPatches.sh && ./initSetupKolabPatches.sh 29 | # we cannot run setup-kolab here, because systemd is not running yet 30 | #RUN setup-kolab --default -mysqlserver=new --timezone=Europe/Brussels --directory-manager-pwd=test 31 | #RUN ./initHttpTunnel.sh 32 | #RUN ./initSSL.sh test.example.org 33 | 34 | VOLUME [ "/sys/fs/cgroup" ] 35 | 36 | # allow connections on port 443 (https) 37 | EXPOSE 443 38 | 39 | ENTRYPOINT ["/usr/sbin/init"] 40 | 41 | -------------------------------------------------------------------------------- /kolab/addDomain.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -z "$1" ] 4 | then 5 | echo "call $0 " 6 | exit 1 7 | fi 8 | 9 | DOM=$1 10 | DC=$(echo -n $DOM | sed 's/\./,dc=/g' | sed 's/^/dc=/') 11 | 12 | echo "[$DOM] 13 | base_dn = $DC 14 | primary_mail = %(givenname)s.%(surname)s@%(domain)s 15 | " >> /etc/kolab/kolab.conf 16 | 17 | # different service-names on CentOS (httpd) and Debian (apache2) 18 | if which /etc/init.d/apache2; then 19 | /etc/init.d/apache2 reload; 20 | else 21 | service httpd reload; 22 | fi 23 | -------------------------------------------------------------------------------- /kolab/disableCanonification.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # remove canonification 4 | # we can only keep canonification if Cyrus was built with the patch 5 | # https://github.com/TBits/KolabScripts/blob/Kolab16/kolab/patches/cyrus_canonification_multiple_domains.patch 6 | # which has been accepted upstream: 7 | # https://github.com/cyrusimap/cyrus-imapd/commit/1e21647e0741b41c3607de54ab8cda6414deabaa#diff-a53b51d7c393e8407ee2e194ab397f0f 8 | 9 | sed -i \ 10 | -e 's/^auth_mech/#auth_mech/g' \ 11 | -e 's/^pts_module/#pts_module/g' \ 12 | -e 's/^ldap_/#ldap_/g' \ 13 | /etc/imapd.conf 14 | sed -i \ 15 | -e 's/ptloader/#ptloader/g' \ 16 | /etc/cyrus.conf 17 | 18 | service cyrus-imapd restart 19 | -------------------------------------------------------------------------------- /kolab/disableGuam.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SCRIPTSPATH=`dirname ${BASH_SOURCE[0]}` 4 | source $SCRIPTSPATH/lib.sh 5 | 6 | DetermineOS 7 | InstallWgetAndPatch 8 | DeterminePythonPath 9 | 10 | ############################################ 11 | # disable guam if it does not work 12 | # eg https://git.kolab.org/T1305 13 | ############################################ 14 | 15 | systemctl stop guam 16 | systemctl disable guam 17 | 18 | systemctl stop cyrus-imapd 19 | 20 | # make sure that cyrus is listening on 993 and 143 instead of 9993 21 | sed -r -i \ 22 | -e 's#imaps.*9993.*#imap cmd="imapd" listen="imap" prefork=5\n imaps cmd="imapd -s" listen="imaps" prefork=1#g' \ 23 | /etc/cyrus.conf 24 | 25 | systemctl start cyrus-imapd 26 | -------------------------------------------------------------------------------- /kolab/disableSpamFilter.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SCRIPTSPATH=`dirname ${BASH_SOURCE[0]}` 4 | source $SCRIPTSPATH/lib.sh 5 | 6 | DetermineOS 7 | InstallWgetAndPatch 8 | DeterminePythonPath 9 | 10 | if [ -z $APPLYPATCHES ] 11 | then 12 | APPLYPATCHES=1 13 | fi 14 | 15 | ##################################################################################### 16 | # disable the spam filter, if it is not needed 17 | ##################################################################################### 18 | 19 | 20 | if [ $APPLYPATCHES -eq 1 ]; then 21 | echo "disabling amavis and clamd" 22 | patch -p1 -i `pwd`/patches/disableSpamFilter.patch -d $pythonDistPackages || exit -1 23 | patch -p1 -i `pwd`/patches/disableSpamFilter2.patch -d /usr || exit -1 24 | fi 25 | -------------------------------------------------------------------------------- /kolab/imapproxy/imapproxy.conf: -------------------------------------------------------------------------------- 1 | ## imapproxy.conf 2 | ## 3 | ## This is the global configuration file for SquirrelMail IMAP Proxy. 4 | ## Lines beginning with a '#' sign are treated as comments and will be 5 | ## ignored. Each line to be processed must be a space delimited 6 | ## keyword/value pair. 7 | ## 8 | 9 | # 10 | ## server_hostname 11 | ## 12 | ## This setting controls which IMAP server we proxy our connections to. 13 | # 14 | server_hostname localhost 15 | 16 | 17 | # 18 | ## connect_retries 19 | ## 20 | ## This setting controls how many times we retry connecting to our server. 21 | ## The delay between retries is configurable with 'connect_delay' 22 | # 23 | connect_retries 10 24 | connect_delay 5 25 | 26 | # 27 | ## cache_size 28 | ## 29 | ## This setting determines how many in-core IMAP connection structures 30 | ## will be allocated. As such, it determines not only how many cached 31 | ## connections will be allowed, but really the total number of simultaneous 32 | ## connections, cached and active. 33 | # 34 | cache_size 3072 35 | 36 | 37 | # 38 | ## listen_port 39 | ## 40 | ## This setting specifies which port the proxy server will bind to and 41 | ## accept incoming connections from. 42 | # 43 | listen_port 8143 44 | 45 | 46 | # 47 | ## listen_address 48 | ## 49 | ## This setting specifies which address the proxy server will bind to and 50 | ## accept incoming connections to. If undefined, bind to all. 51 | ## Must be a dotted decimal IP address. 52 | # 53 | listen_address 127.0.0.1 54 | 55 | 56 | # 57 | ## server_port 58 | ## 59 | ## This setting specifies the port that server_hostname is listening on. 60 | ## This is the tcp port that we proxy inbound connections to. 61 | ## 62 | ## If you are using SSL with IMAP Proxy, note that unless the server is 63 | ## highly non-standard, this should still be set to the server's normal, 64 | ## unencrypted IMAP port and should NOT be set to port 993, since IMAP 65 | ## Proxy uses STARTTLS to encrypt a "normal" IMAP connection. 66 | ## 67 | ## If the server is only available via (encrypted) port 993, please 68 | ## consult the README.ssl file for help. 69 | # 70 | server_port 143 71 | 72 | # 73 | ## cache_expiration_time 74 | ## 75 | ## This setting controls how many seconds an inactive connection will be 76 | ## cached. 77 | # 78 | cache_expiration_time 300 79 | 80 | 81 | # 82 | ## proc_username 83 | ## 84 | ## This setting controls which username the IMAP proxy process will run as. 85 | ## It is not allowed to run as "root". 86 | # 87 | proc_username nobody 88 | 89 | # 90 | ## proc_groupname 91 | ## 92 | ## This setting controls which groupname the IMAP proxy process will run as. 93 | # 94 | proc_groupname nobody 95 | 96 | 97 | # 98 | ## stat_filename 99 | ## 100 | ## This is the path to the filename that the proxy server mmap()s to 101 | ## write statistical data to. This is the file that pimpstat needs to 102 | ## look at to be able to provide his useful stats. 103 | # 104 | stat_filename /var/run/pimpstats 105 | 106 | 107 | # 108 | ## protocol_log_filename 109 | ## 110 | ## protocol logging may only be turned on for one user at a time. All 111 | ## protocol logging data is written to the file specified by this path. 112 | # 113 | protocol_log_filename /var/log/imapproxy_protocol.log 114 | 115 | 116 | # 117 | ## syslog_facility 118 | ## 119 | ## The logging facility to be used for all syslog calls. If nothing is 120 | ## specified here, it will default to LOG_MAIL. Any of the possible 121 | ## facilities listed in the syslog(3C) manpage may be used here except 122 | ## LOG_KERN. 123 | # 124 | syslog_facility LOG_MAIL 125 | 126 | 127 | # 128 | ## syslog_prioritymask 129 | ## 130 | ## This configuration option is provided as a way to limit the verbosity 131 | ## of squirrelmail-imap_proxy. If no value is specified, it will default 132 | ## to no priority mask and you'll see all possible log messages. Any of 133 | ## the possible priority values listed in the syslog(3C) manpage may be 134 | ## used here. By default, I've left this commented out so you will see 135 | ## all possible log messages. 136 | # 137 | #syslog_prioritymask LOG_WARNING 138 | 139 | 140 | # 141 | ## send_tcp_keepalives 142 | ## 143 | ## This determines whether the SO_KEEPALIVE option will be set on all 144 | ## sockets. 145 | # 146 | send_tcp_keepalives no 147 | 148 | 149 | # 150 | ## enable_select_cache 151 | ## 152 | ## This configuration option allows you to turn select caching on or off. 153 | ## When select caching is enabled, squirrelmail-imap_proxy will cache SELECT 154 | ## responses from an IMAP server. 155 | # 156 | enable_select_cache no 157 | 158 | 159 | # 160 | ## foreground_mode 161 | ## 162 | ## This will prevent squirrelmail-imap_proxy from detaching from his parent 163 | ## process and controlling terminal on startup. 164 | # 165 | foreground_mode no 166 | 167 | 168 | # 169 | ## force_tls 170 | ## 171 | ## Force squirrelmail-imap_proxy to use STARTTLS even if LOGIN is not disabled. 172 | # 173 | force_tls yes 174 | 175 | 176 | # 177 | ## chroot_directory 178 | ## 179 | ## This allows squirrelmail-imap_proxy to run in a chroot jail if desired. 180 | ## If commented out, squirrelmail-imap_proxy will not run chroot()ed. If 181 | ## a directory is specified here, squirrelmail-imap_proxy will chroot() to 182 | ## that directory. 183 | # 184 | #chroot_directory /var/empty 185 | 186 | 187 | # 188 | ## preauth_command 189 | ## 190 | ## Arbitrary command that can be sent to the server before 191 | ## authenticating users. This can be useful to access non- 192 | ## standard IMAP servers such as Yahoo!, which requires the 193 | ## following command to be sent before authentication is allowed: 194 | ## ID ("GUID" "1") 195 | ## (See: http://en.wikipedia.org/wiki/Yahoo!_Mail#Free_IMAP_and_SMTPs_access ) 196 | ## To use such a command, this setting should look like this: 197 | ## preauth_command ID ("GUID" "1") 198 | ## No matter what this command is, it is expected to return an 199 | ## OK response 200 | # 201 | #preauth_command 202 | 203 | 204 | # 205 | ## enable_admin_commands 206 | ## 207 | ## Used to enable or disable the internal squirrelmail-imap_proxy 208 | ## administrative commands. 209 | # 210 | enable_admin_commands no 211 | 212 | 213 | # 214 | ## Various path options for SSL CA certificates/directories 215 | # 216 | #tls_ca_file /usr/share/ssl/certs/ca-bundle.crt 217 | #tls_ca_path /usr/share/ssl/certs/ 218 | #tls_cert_file /usr/share/ssl/certs/mycert.crt 219 | #tls_key_file /usr/share/ssl/certs/mycert.key 220 | 221 | 222 | # 223 | ## Authenticate using SASL AUTHENTICATE PLAIN 224 | ## 225 | ## The following authentication username and password are used 226 | ## along with the username from the client as the authorization 227 | ## identity. In order to avoid having the service wide open (no 228 | ## password needed from the client), the client is required to 229 | ## send the auth_shared_secret in leiu of a user password. 230 | ## 231 | ## NOTE: This functionality *assumes* that the server supports 232 | ## AUTHENTICATE PLAIN, and it does *not* verify this by 233 | ## looking at the server's capabilities list. 234 | # 235 | #auth_sasl_plain_username 236 | #auth_sasl_plain_password 237 | #auth_shared_secret 238 | 239 | 240 | -------------------------------------------------------------------------------- /kolab/imapproxy/nginx.conf: -------------------------------------------------------------------------------- 1 | worker_processes 1; 2 | 3 | events { 4 | worker_connections 1024; 5 | } 6 | 7 | error_log /var/log/nginx/error.log info; 8 | 9 | mail { 10 | auth_http localhost:81/auth; 11 | 12 | proxy on; 13 | 14 | server { 15 | listen 143; 16 | protocol imap; 17 | } 18 | } 19 | 20 | http { 21 | server { 22 | listen localhost:81; 23 | location = /auth { 24 | add_header Auth-Status OK; 25 | add_header Auth-Server 127.0.0.1; # backend ip 26 | add_header Auth-Port 8993; # backend port 27 | return 200; 28 | } 29 | } 30 | } 31 | 32 | -------------------------------------------------------------------------------- /kolab/imapproxy/stunnel: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # stunnel SysV startup file 3 | # Copyright by Michal Trojnara 2002,2007,2008 4 | 5 | PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin 6 | DAEMON=/usr/bin/stunnel 7 | PIDFILE=/var/run/stunnel/stunnel.pid 8 | 9 | # Source function library. 10 | . /etc/rc.d/init.d/functions 11 | 12 | test -f $DAEMON || exit 0 13 | 14 | case "$1" in 15 | start) 16 | echo -n "Starting universal SSL tunnel: stunnel" 17 | daemon $DAEMON || echo -n " failed" 18 | echo "." 19 | ;; 20 | stop) 21 | echo -n "Stopping universal SSL tunnel: stunnel" 22 | if test -r $PIDFILE; then 23 | kill `cat $PIDFILE` 2> /dev/null || echo -n " failed" 24 | else 25 | echo -n " no PID file" 26 | fi 27 | echo "." 28 | ;; 29 | restart|force-reload) 30 | echo "Restarting universal SSL tunnel" 31 | $0 stop 32 | sleep 1 33 | $0 start 34 | echo "done." 35 | ;; 36 | *) 37 | N=${0##*/} 38 | N=${N#[SK]??} 39 | echo "Usage: $N {start|stop|restart|force-reload}" >&2 40 | exit 1 41 | ;; 42 | esac 43 | 44 | exit 0 45 | 46 | -------------------------------------------------------------------------------- /kolab/imapproxy/stunnel.conf: -------------------------------------------------------------------------------- 1 | ; Protocol version (all, SSLv2, SSLv3, TLSv1) 2 | sslVersion = TLSv1 3 | 4 | ; Some security enhancements for UNIX systems - comment them out on Win32 5 | chroot = /var/run/stunnel/ 6 | setuid = nobody 7 | setgid = nobody 8 | pid = /stunnel.pid 9 | 10 | ; Some performance tunings 11 | socket = l:TCP_NODELAY=1 12 | socket = r:TCP_NODELAY=1 13 | 14 | ; Use it for client mode 15 | client = yes 16 | ; foreground = yes 17 | 18 | ; Service-level configuration 19 | 20 | [imaps] 21 | accept = 8993 22 | connect = 993 23 | 24 | -------------------------------------------------------------------------------- /kolab/initHttpTunnel.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ##################################################################################### 4 | # make sure that kolab webadmin works even on my virtual machine with routed port 80 5 | ##################################################################################### 6 | sed -r -i \ 7 | -e '/api_url/d' \ 8 | -e "s#\[kolab_wap\]#[kolab_wap]\napi_url = http://localhost/kolab-webadmin/api#g" \ 9 | /etc/kolab/kolab.conf 10 | 11 | sed -i -e "s#?># \$config['kolab_files_server_url'] = 'http://localhost/chwala/';\n\n?>#g" /etc/roundcubemail/config.inc.php 12 | -------------------------------------------------------------------------------- /kolab/initIMAPProxy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | proxy=up-imapproxy 4 | #proxy=nginx 5 | 6 | if [[ "$proxy" = "up-imapproxy" ]] 7 | then 8 | yum install -y up-imapproxy 9 | cp imapproxy/imapproxy.conf /etc/ 10 | service imapproxy start 11 | chkconfig imapproxy on 12 | fi 13 | 14 | if [[ "$proxy" = "nginx" ]] 15 | then 16 | yum install -y stunnel nginx 17 | cp imapproxy/stunnel.conf /etc/stunnel/stunnel.conf 18 | cp imapproxy/stunnel /etc/init.d/stunnel 19 | chmod a+x /etc/init.d/stunnel 20 | service stunnel start 21 | chkconfig stunnel on 22 | 23 | cp imapproxy/nginx.conf /etc/nginx/nginx.conf 24 | service nginx start 25 | chkconfig nginx on 26 | fi 27 | 28 | # change configuration of roundcube, now use the imap proxy 29 | sed -i "s/config\['default_port'\] = 143/config['default_port'] = 8143/g" /etc/roundcubemail/config.inc.php 30 | 31 | -------------------------------------------------------------------------------- /kolab/initMailCatchall.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ##################################################################################### 4 | # enable catchall mail addresses 5 | ##################################################################################### 6 | 7 | filename=/etc/postfix/ldap/virtual_alias_maps_catchall.cf 8 | filename_3=/etc/postfix/ldap/virtual_alias_maps_catchall_3.cf 9 | cp /etc/postfix/ldap/virtual_alias_maps.cf $filename 10 | sed -i -e 's#^query_filter = .*#query_filter = (\&(alias=catchall@%d)(objectclass=inetorgperson))#g' $filename 11 | 12 | cp /etc/postfix/ldap/virtual_alias_maps_3.cf $filename_3 13 | sed -i -e 's#^query_filter = .*#query_filter = (\&(alias=catchall@%d)(objectclass=inetorgperson))#g' $filename_3 14 | 15 | sed -i -e "s#^virtual_alias_maps = \(.*\)#virtual_alias_maps = \1, ldap:$filename, ldap:$filename_3#" /etc/postfix/main.cf 16 | 17 | postmap $filename 18 | postmap $filename_3 19 | service postfix restart 20 | -------------------------------------------------------------------------------- /kolab/initMailForward.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ##################################################################################### 4 | # enable mail forwarding only users 5 | ##################################################################################### 6 | 7 | cp /etc/postfix/ldap/virtual_alias_maps.cf /etc/postfix/ldap/virtual_alias_maps_forward.cf 8 | sed -i -e 's#^query_filter = .*#query_filter = (\&(|(mail=%s)(alias=%s))(objectclass=inetorgperson))#g' /etc/postfix/ldap/virtual_alias_maps_forward.cf 9 | sed -i -e 's#^result_attribute = .*#result_attribute = mailForwardingAddress#g' /etc/postfix/ldap/virtual_alias_maps_forward.cf 10 | 11 | cp /etc/postfix/ldap/virtual_alias_maps_3.cf /etc/postfix/ldap/virtual_alias_maps_forward_3.cf 12 | sed -i -e 's#^query_filter = .*#query_filter = (\&(|(mail=%s)(alias=%s))(objectclass=inetorgperson))#g' /etc/postfix/ldap/virtual_alias_maps_forward_3.cf 13 | sed -i -e 's#^result_attribute = .*#result_attribute = mailForwardingAddress#g' /etc/postfix/ldap/virtual_alias_maps_forward_3.cf 14 | 15 | sed -i -e 's#ldap:/etc/postfix/ldap/virtual_alias_maps.cf#ldap:/etc/postfix/ldap/virtual_alias_maps.cf, ldap:/etc/postfix/ldap/virtual_alias_maps_forward.cf#' /etc/postfix/main.cf 16 | sed -i -e 's#ldap:/etc/postfix/ldap/virtual_alias_maps_3.cf#ldap:/etc/postfix/ldap/virtual_alias_maps_3.cf, ldap:/etc/postfix/ldap/virtual_alias_maps_forward_3.cf#' /etc/postfix/main.cf 17 | 18 | service postfix restart 19 | 20 | -------------------------------------------------------------------------------- /kolab/initMultiDomain.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SCRIPTSPATH=`dirname ${BASH_SOURCE[0]}` 4 | source $SCRIPTSPATH/lib.sh 5 | 6 | DetermineOS 7 | InstallWgetAndPatch 8 | DeterminePythonPath 9 | 10 | ##################################################################################### 11 | # Prepare Canonification for Cyrus IMAP 12 | ##################################################################################### 13 | cp -f /etc/imapd.conf /etc/imapd.conf.beforeMultiDomain 14 | sed -i -e "s#ldap_base: .*#ldap_base: dc=%2,dc=%1#g" /etc/imapd.conf 15 | sed -i -e "s#ldap_group_base: .*#ldap_group_base: dc=%2,dc=%1#g" /etc/imapd.conf 16 | sed -i -e "s#ldap_member_base: .*#ldap_member_base: ou=People,dc=%2,dc=%1#g" /etc/imapd.conf 17 | 18 | echo "ldap_domain_base_dn: cn=kolab,cn=config 19 | ldap_domain_filter: (&(objectclass=domainrelatedobject)(associateddomain=%s)) 20 | ldap_domain_name_attribute: associatedDomain 21 | ldap_domain_scope: sub 22 | ldap_domain_result_attribute: inetdomainbasedn" >> /etc/imapd.conf 23 | 24 | service cyrus-imapd restart 25 | 26 | #enable unique ids across domains, to allow login with uid 27 | sed -r -i -e "s#\[kolab\]#[kolab]\nunique_uid_across_domains=true#g" /etc/kolab/kolab.conf 28 | 29 | ##################################################################################### 30 | #Update Postfix LDAP Lookup Tables 31 | # support subdomains too, search_base = dc=%3,dc=%2,dc=%1 32 | # see https://lists.kolab.org/pipermail/users/2013-January/014233.html 33 | ##################################################################################### 34 | 35 | cp -Rf /etc/postfix/ldap /etc/postfix/ldap.beforeMultiDomain 36 | rm -f /etc/postfix/ldap/*_3.cf 37 | for f in `find /etc/postfix/ldap/ -type f -name "*.cf"`; 38 | do 39 | f3=${f/.cf/_3.cf} 40 | cp $f $f3 41 | if [[ "/etc/postfix/ldap/mydestination.cf" == "$f" ]] 42 | then 43 | sed -r -i -e 's/^query_filter = .*$/query_filter = (\&(associateddomain=%s)(associateddomain=*.*.*))/g' $f3 44 | else 45 | sed -r -i -e 's/^search_base = .*$/search_base = dc=%2,dc=%1/g' $f 46 | sed -r -i -e 's/^search_base = .*$/search_base = dc=%3,dc=%2,dc=%1/g' $f3 47 | sed -r -i -e 's#^domain = .*$#domain = ldap:/etc/postfix/ldap/mydestination_3.cf#g' $f3 48 | fi 49 | done 50 | 51 | cp -f /etc/postfix/main.cf /etc/postfix/main.cf.beforeMultiDomain 52 | sed -r -i -e 's#transport_maps.cf#transport_maps.cf, ldap:/etc/postfix/ldap/transport_maps_3.cf#g' /etc/postfix/main.cf 53 | sed -i -e 's#virtual_alias_maps.cf#virtual_alias_maps.cf, ldap:/etc/postfix/ldap/virtual_alias_maps_3.cf, ldap:/etc/postfix/ldap/mailenabled_distgroups_3.cf, ldap:/etc/postfix/ldap/mailenabled_dynamic_distgroups_3.cf, ldap:/etc/postfix/ldap/virtual_alias_maps_sharedfolders_3.cf#' /etc/postfix/main.cf 54 | sed -r -i -e 's#local_recipient_maps.cf#local_recipient_maps.cf, ldap:/etc/postfix/ldap/local_recipient_maps_3.cf#g' /etc/postfix/main.cf 55 | 56 | # create a file that can be manipulated manually to allow aliases across domains; 57 | # eg. user mymailbox@test.de gets emails that are sent to myalias@test2.de; 58 | # You can also enable aliases for domains here to receive emails properly, eg. @test2.de @test.de; 59 | # You need to run postmap on the file after manually changing it! 60 | postfix_virtual_file=/etc/postfix/virtual_alias_maps_manual.cf 61 | if [ ! -f $postfix_virtual_file ] 62 | then 63 | echo "# you can manually set aliases, across domains. " > $postfix_virtual_file 64 | echo "# for example: " >> $postfix_virtual_file 65 | echo "#myalias@test2.de mymailbox@test.de" >> $postfix_virtual_file 66 | echo "#@test4.de @test.de" >> $postfix_virtual_file 67 | echo "#@pokorra.it timotheus.pokorra@test1.de" >> $postfix_virtual_file 68 | fi 69 | sed -i -e "s#virtual_alias_maps.cf#virtual_alias_maps.cf, hash:$postfix_virtual_file#" /etc/postfix/main.cf 70 | postmap $postfix_virtual_file 71 | 72 | service postfix restart 73 | 74 | ##################################################################################### 75 | #kolab_auth conf roundcube; see https://git.kolab.org/roundcubemail-plugins-kolab/commit/?id=1778b5ec70156f064fdda61c817c678001406996 76 | ##################################################################################### 77 | cp -r /etc/roundcubemail/kolab_auth.inc.php /etc/roundcubemail/kolab_auth.inc.php.beforeMultiDomain 78 | sed -r -i -e "s#=> 389,#=> 389,\n 'domain_base_dn' => 'cn=kolab,cn=config',\n 'domain_filter' => '(\&(objectclass=domainrelatedobject)(associateddomain=%s))',\n 'domain_name_attr' => 'associateddomain',#g" /etc/roundcubemail/kolab_auth.inc.php 79 | sed -r -i -e "s#'ou=People,.*'#'ou=People,%dc'#g" /etc/roundcubemail/kolab_auth.inc.php 80 | sed -r -i -e "s#'ou=Groups,.*'#'ou=Groups,%dc'#g" /etc/roundcubemail/kolab_auth.inc.php 81 | 82 | ##################################################################################### 83 | #enable freebusy for all domains 84 | ##################################################################################### 85 | sed -r -i -e "s#base_dn = .*#base_dn = %dc#g" /usr/share/kolab-freebusy/config/config.ini 86 | 87 | ##################################################################################### 88 | #auto created folders: do not use an extra partition for the archive folder. 89 | #see https://issues.kolab.org/show_bug.cgi?id=3210 90 | ##################################################################################### 91 | sed -r -i -e "s#'quota': 0,##g" /etc/kolab/kolab.conf 92 | sed -r -i -e "s#'partition': 'archive'##g" /etc/kolab/kolab.conf 93 | 94 | ##################################################################################### 95 | # Fix Global Address Book in Multi Domain environment 96 | #################################################################################### 97 | cp -r /etc/roundcubemail/config.inc.php /etc/roundcubemail/config.inc.php.beforeMultiDomain 98 | sed -r -i -e "s#'ou=People,.*'#'ou=People,%dc'#g" /etc/roundcubemail/config.inc.php 99 | sed -r -i -e "s#'ou=Groups,.*'#'ou=Groups,%dc'#g" /etc/roundcubemail/config.inc.php 100 | 101 | ##################################################################################### 102 | #set primary_mail value in kolab section, so that new users in a different domain will have a proper primary email address, even without changing kolab.conf for each domain 103 | ##################################################################################### 104 | sed -r -i -e "s/primary_mail = .*/primary_mail = %(givenname)s.%(surname)s@%(domain)s/g" /etc/kolab/kolab.conf 105 | 106 | ##################################################################################### 107 | #make sure that for alias domains, the emails will actually arrive, by checking the postfix file 108 | #see https://issues.kolab.org/show_bug.cgi?id=2658 109 | ##################################################################################### 110 | sed -r -i -e "s#\[kolab\]#[kolab]\npostfix_virtual_file = $postfix_virtual_file#g" /etc/kolab/kolab.conf 111 | 112 | ##################################################################################### 113 | #avoid a couple of warnings by setting default values 114 | ##################################################################################### 115 | sed -r -i -e "s#\[ldap\]#[ldap]\nmodifytimestamp_format = %%Y%%m%%d%%H%%M%%SZ#g" /etc/kolab/kolab.conf 116 | sed -r -i -e "s/\[cyrus-imap\]/[imap]\nvirtual_domains = userid\n\n[cyrus-imap]/g" /etc/kolab/kolab.conf 117 | 118 | ##################################################################################### 119 | # install memcache to improve WAP login speed if many domains are present 120 | ##################################################################################### 121 | if [[ $OS == CentOS* || $OS == Fedora* ]] 122 | then 123 | yum -y install php-pecl-memcache memcached 124 | elif [[ $OS == Debian* || $OS == Ubuntu* ]] 125 | then 126 | apt-get -y install php5-memcache memcached 127 | fi 128 | 129 | systemctl start memcached 130 | systemctl enable memcached 131 | sed -r -i -e "s#\[kolab_wap\]#[kolab_wap]\nmemcache_hosts = 127.0.0.1:11211\nmemcache_pconnect = true#g" /etc/kolab/kolab.conf 132 | 133 | ##################################################################################### 134 | # apply a couple of patches, see related kolab bugzilla number in filename, eg. https://issues.kolab.org/show_bug.cgi?id=1869 135 | ##################################################################################### 136 | 137 | if [ ! -d patches ] 138 | then 139 | mkdir -p patches 140 | echo Downloading patch validateAliasDomainPostfixVirtualFileBug2658.patch 141 | wget $patchesurl/validateAliasDomainPostfixVirtualFileBug2658.patch -O patches/validateAliasDomainPostfixVirtualFileBug2658.patch 142 | wget $patchesurl/canonification_via_uid_wap.patch -O patches/canonification_via_uid_wap.patch 143 | wget $patchesurl/canonification_via_uid_roundcube.patch -O patches/canonification_via_uid_roundcube.patch 144 | wget $patchesurl/canonification_via_uid_pykolab.patch -O patches/canonification_via_uid_pykolab.patch 145 | fi 146 | 147 | if [ -z $APPLYPATCHES ] 148 | then 149 | APPLYPATCHES=1 150 | fi 151 | 152 | if [ $APPLYPATCHES -eq 1 ] 153 | then 154 | patch -p1 --fuzz=0 -i `pwd`/patches/validateAliasDomainPostfixVirtualFileBug2658.patch -d /usr/share/kolab-webadmin || exit -1 155 | patch -p1 --fuzz=0 -i `pwd`/patches/canonification_via_uid_wap.patch -d /usr/share/kolab-webadmin || exit -1 156 | patch -p1 --fuzz=0 -i `pwd`/patches/canonification_via_uid_roundcube.patch -d /usr/share/roundcubemail || exit -1 157 | patch -p1 --fuzz=0 -i `pwd`/patches/canonification_via_uid_pykolab.patch -d $pythonDistPackages || exit -1 158 | fi 159 | 160 | service kolab-saslauthd restart 161 | 162 | KolabService restart 163 | -------------------------------------------------------------------------------- /kolab/initRoundcubePlugins.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SCRIPTSPATH=`dirname ${BASH_SOURCE[0]}` 4 | source $SCRIPTSPATH/lib.sh 5 | 6 | DetermineOS 7 | InstallWgetAndPatch 8 | 9 | # disable the message_label plugin, because Kolab 3.3 has tags for emails 10 | if [ 1 -eq 0 ]; 11 | then 12 | ##################################################################################### 13 | # install our modified version of the message_label plugin to support virtual folders aka imap flags 14 | # see https://github.com/tpokorra/message_label/tree/message_label_tbits 15 | ##################################################################################### 16 | wget https://github.com/tpokorra/message_label/archive/message_label_tbits.tar.gz -O message_label.tar.gz 17 | tar -xzf message_label.tar.gz 18 | rm -f message_label.tar.gz 19 | mv message_label-message_label_tbits /usr/share/roundcubemail/plugins/message_label 20 | cp -f /etc/roundcubemail/config.inc.php /etc/roundcubemail/config.inc.php.beforeMultiDomain 21 | sed -r -i -e "s#'redundant_attachments',#'redundant_attachments',\n 'message_label',#g" /etc/roundcubemail/config.inc.php 22 | # probably a dirty hack: we need to force fetching the headers, so that the labels are always displayed 23 | cp -f /usr/share/roundcubemail/program/lib/Roundcube/rcube_imap.php /usr/share/roundcubemail/program/lib/Roundcube/rcube_imap.php.beforeMultiDOmain 24 | sed -i -e 's#function fetch_headers($folder, $msgs, $sort = true, $force = false)#function fetch_headers($folder, $msgs, $sort = true, $forcedummy = false, $force = true)#g' /usr/share/roundcubemail/program/lib/Roundcube/rcube_imap.php 25 | 26 | ##################################################################################### 27 | # apply a patch to roundcube plugin managesieve, to support the labels set with message_label plugin. 28 | # see https://github.com/tpokorra/roundcubemail/commits/manage_sieve_using_message_label_flags 29 | ##################################################################################### 30 | mkdir -p patches 31 | echo Downloading patch managesieveWithMessagelabel.patch... 32 | wget https://raw.github.com/tpokorra/kolab3_tbits_scripts/master/kolab3.1/patches/managesieveWithMessagelabel.patch 33 | mv managesieveWithMessagelabel.patch patches/ 34 | patch -p1 -i `pwd`/patches/managesieveWithMessagelabel.patch -d /usr/share/roundcubemail 35 | fi 36 | 37 | ##################################################################################### 38 | # install the advanced_search plugin 39 | # see https://github.com/GMS-SA/roundcube-advanced-search 40 | ##################################################################################### 41 | wget https://github.com/GMS-SA/roundcube-advanced-search/archive/stable.tar.gz -O advanced_search.tar.gz 42 | tar -xzf advanced_search.tar.gz 43 | rm -f advanced_search.tar.gz 44 | #pluginsPath=/usr/share/roundcubemail/public_html/assets/plugins 45 | pluginsPath=/usr/share/roundcubemail/plugins 46 | mv roundcube-advanced-search-stable $pluginsPath/advanced_search 47 | mv $pluginsPath/advanced_search/config-default.inc.php $pluginsPath/advanced_search/config.inc.php 48 | sed -r -i -e "s#messagemenu#toolbar#g" $pluginsPath/advanced_search/config.inc.php 49 | sed -r -i -e "s#'redundant_attachments',#'redundant_attachments',\n 'advanced_search',#g" /etc/roundcubemail/config.inc.php 50 | 51 | -------------------------------------------------------------------------------- /kolab/initSetupKolabPatches.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SCRIPTSPATH=`dirname ${BASH_SOURCE[0]}` 4 | source $SCRIPTSPATH/lib.sh 5 | 6 | DetermineOS 7 | InstallWgetAndPatch 8 | DeterminePythonPath 9 | 10 | ##################################################################################### 11 | # apply a couple of patches, see related kolab bugzilla number in filename, eg. https://issues.kolab.org/show_bug.cgi?id=2018 12 | ##################################################################################### 13 | 14 | if [ -z $APPLYPATCHES ] 15 | then 16 | APPLYPATCHES=1 17 | fi 18 | 19 | if [ $APPLYPATCHES -eq 1 ] 20 | then 21 | echo "applying patch for Roundcube Kolab plugin for storage in MariaDB" 22 | patch -p1 --fuzz=0 -i `pwd`/patches/roundcubeStorageMariadbBug4883.patch -d /usr/share/roundcubemail || exit -1 23 | 24 | # TODO: see if we still need these patches 25 | #echo "applying patch for waiting after restart of dirsrv (necessary on Debian)" 26 | #patch -p1 --fuzz=0 -i `pwd`/patches/setupKolabSleepDirSrv.patch -d $pythonDistPackages || exit -1 27 | 28 | # https://github.com/TBits/KolabScripts/issues/76 29 | echo "fix problem on LXC containers with access to TCP keepalive settings" 30 | patch -p1 --fuzz=0 -i `pwd`/patches/fixPykolabIMAPKeepAlive.patch -d $pythonDistPackages || exit -1 31 | 32 | echo "apply patch for Etc timezone in roundcube plugins/calendar" 33 | patch -p1 --fuzz=0 -i `pwd`/patches/roundcube_calendar_etc_timezone_T2666.patch -d /usr/share/roundcubemail || exit -1 34 | # another way to fix it, in the jstz library (see also https://bitbucket.org/pellepim/jstimezonedetect/issues/168/ignore-timezones-like-etc-gmt-1) 35 | sed -i 's#"UTC"===a)#"UTC"===a)\&\&a.indexOf("Etc")<0#' /usr/share/roundcubemail/public_html/assets/program/js/jstz.min.js 36 | 37 | echo "do not rename existing mailboxes" 38 | patch -p1 --fuzz=0 -i `pwd`/patches/pykolab_do_not_rename_existing_mailbox_T3315.patch -d $pythonDistPackages || exit -1 39 | 40 | echo "kolab lam should cope with invalid mailbox names more gracefully" 41 | patch -p1 --fuzz=0 -i `pwd`/patches/kolab_lam_invalid_mailbox_name.patch -d $pythonDistPackages || exit -1 42 | 43 | fi 44 | 45 | if [[ $OS == Debian* ]] 46 | then 47 | # workaround for bug 2050, https://issues.kolab.org/show_bug.cgi?id=2050 48 | echo "export ZEND_DONT_UNLOAD_MODULES=1" >> /etc/apache2/envvars 49 | 50 | # TODO on Debian, we need to install the rewrite for the csrf token 51 | newConfigLines="\tRewriteEngine On\n \ 52 | \tRewriteRule ^/roundcubemail/[a-f0-9]{16}/(.*) /roundcubemail/\$1 [PT,L]\n \ 53 | \tRewriteRule ^/webmail/[a-f0-9]{16}/(.*) /webmail/\$1 [PT,L]\n \ 54 | \tRedirectMatch ^/$ /roundcubemail/\n" 55 | 56 | # sed -i -e "s~~$newConfigLines~" /etc/apache2/sites-enabled/000-default 57 | fi 58 | 59 | if [[ $OS == CentOS* || $OS == Fedora* ]] 60 | then 61 | if [[ "`rpm -qa | grep guam`" != "" ]] 62 | then 63 | systemctl start guam || exit -1 64 | fi 65 | # we need a fully qualified hostname for amavisd to restart successfully, and later for setting up the ldap as well. 66 | # on LXD, the container name is not allowed a dot in the name. therefore we need to set the hostname here 67 | hostname=`hostname -f` 68 | hostname=${hostname//-/.} 69 | # but only use maximum two subdomains for the host, so that the email address will be @subdomain.domain.tld 70 | DOTS=${hostname//[^.]}; 71 | while [[ ${#DOTS} -gt 3 ]]; do hostname="${hostname#*.}"; DOTS=${hostname//[^.]}; done 72 | hostnamectl set-hostname $hostname 73 | 74 | # there is an issue with lxc 2.0.8 and CentOS, with PrivateDevices 75 | # https://github.com/lxc/lxc/issues/1623 76 | # journalctl -xe shows: 77 | # -- Unit amavisd.service has begun starting up. 78 | # systemd[3849]: Failed at step NAMESPACE spawning /usr/sbin/amavisd: Invalid argument 79 | # -- Subject: Process /usr/sbin/amavisd could not be executed 80 | if [ -f /usr/lib/systemd/system/amavisd.service ]; then 81 | sed -i 's/PrivateDevices=true/#PrivateDevices=true/g' /usr/lib/systemd/system/amavisd.service 82 | systemctl daemon-reload 83 | systemctl restart amavisd.service 84 | fi 85 | else 86 | if [[ "`dpkg -l | grep guam`" != "" ]] 87 | then 88 | systemctl start guam || exit -1 89 | fi 90 | fi 91 | -------------------------------------------------------------------------------- /kolab/initSleepTimesForTest.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SCRIPTSPATH=`dirname ${BASH_SOURCE[0]}` 4 | source $SCRIPTSPATH/lib.sh 5 | 6 | DetermineOS 7 | InstallWgetAndPatch 8 | DeterminePythonPath 9 | 10 | ##################################################################################### 11 | #reduce the sleep time between adding domains, see https://issues.kolab.org/show_bug.cgi?id=2491 12 | ##################################################################################### 13 | sed -r -i -e "s/\[kolab\]/[kolab]\ndomain_sync_interval = 10/g" /etc/kolab/kolab.conf 14 | 15 | patch -p1 -i `pwd`/patches/sleepTimeDomainTests.patch -d $pythonDistPackages 16 | 17 | if [ -f /bin/systemctl -a -f /etc/debian_version ] 18 | then 19 | /bin/systemctl restart kolab-server 20 | elif [ -f /bin/systemctl ] 21 | then 22 | /bin/systemctl restart kolabd.service 23 | elif [ -f /sbin/service ] 24 | then 25 | service kolabd restart 26 | elif [ -f /usr/sbin/service ] 27 | then 28 | service kolab-server restart 29 | fi 30 | -------------------------------------------------------------------------------- /kolab/initTBitsCustomizationsDE.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SCRIPTSPATH=`dirname ${BASH_SOURCE[0]}` 4 | source $SCRIPTSPATH/lib.sh 5 | 6 | DetermineOS 7 | InstallWgetAndPatch 8 | DeterminePythonPath 9 | 10 | ##################################################################################### 11 | # adjust some settings, that might be specific to TBits 12 | ##################################################################################### 13 | service kolabd stop 14 | service kolab-saslauthd stop 15 | 16 | # add admin_auto_fields_rw = true to kolab_wap section of kolab.conf 17 | sed -r -i -e "s#\[kolab_wap\]#[kolab_wap]\nadmin_auto_fields_rw = true#g" /etc/kolab/kolab.conf 18 | 19 | # add enable_intranet_token to kolab section of kolab.conf 20 | sed -r -i -e "s#\[kolab\]#[kolab]\nenable_intranet_token = test.tbits.net,customerxyz.de#g" /etc/kolab/kolab.conf 21 | 22 | # change default locale 23 | sed -r -i -e "s#default_locale = en_US#default_locale = de_DE#g" /etc/kolab/kolab.conf 24 | 25 | # set in kolab.conf, ldap section: modifytimestamp_format = %%Y%%m%%d%%H%%M%%SZ, to avoid warning on console 26 | sed -r -i -e "s#\[ldap\]#[ldap]\nmodifytimestamp_format = %%Y%%m%%d%%H%%M%%SZ#g" /etc/kolab/kolab.conf 27 | 28 | # do not add secondary emails by default 29 | sed -r -i -e "s#autocreate_folders#secondary_mail = { }\nautocreate_folders#g" /etc/kolab/kolab.conf 30 | 31 | # set in /etc/sysconfig/dirsrv: ulimit -n 32192, to avoid dirsrv crashing because of too many open files 32 | sed -r -i -e "s/# ulimit -n 8192/ulimit -n 32192/g" /etc/sysconfig/dirsrv 33 | sed -r -i -e "s/#ulimit -n 8192/ulimit -n 32192/g" /etc/sysconfig/dirsrv 34 | if [ -f /bin/systemctl ] 35 | then 36 | /bin/systemctl restart dirsrv.target && sleep 10 37 | else 38 | service dirsrv restart 39 | fi 40 | 41 | # disable debug mode in LDAP.php to avoid too much output 42 | sed -r -i -e 's/config_set\("debug", true\)/config_set("debug", false)/g' /usr/share/kolab-webadmin/lib/Auth/LDAP.php 43 | # disable debug modes for roundcube; otherwise /var/log/roundcubemail/imap can get really big! 44 | sed -r -i -e "s/_debug'] = true/_debug'] = false/g" /etc/roundcubemail/config.inc.php 45 | 46 | # change order of addressbooks: first personal address book 47 | sed -r -i -e "s# = 0;# = 1;#g" /etc/roundcubemail/kolab_addressbook.inc.php 48 | 49 | # change default names for calendar and address book 50 | sed -r -i -e "s#Calendar#Kalender#g" /etc/roundcubemail/kolab_folders.inc.php 51 | sed -r -i -e "s#Contacts#Kontakte#g" /etc/roundcubemail/kolab_folders.inc.php 52 | sed -r -i -e "s#Sent#Gesendet#g" /etc/roundcubemail/kolab_folders.inc.php 53 | sed -r -i -e "s#Drafts#Entwürfe#g" /etc/roundcubemail/kolab_folders.inc.php 54 | sed -r -i -e "s#Trash#Papierkorb#g" /etc/roundcubemail/kolab_folders.inc.php 55 | #sed -r -i -e "s#Spam#Spam#g" /etc/roundcubemail/kolab_folders.inc.php 56 | sed -r -i -e "s#kolab_folders_task_default'\] = ''#kolab_folders_task_default'] = 'Aufgaben'#g" /etc/roundcubemail/kolab_folders.inc.php 57 | sed -r -i -e "s#kolab_folders_note_default'\] = ''#kolab_folders_note_default'] = 'Notizen'#g" /etc/roundcubemail/kolab_folders.inc.php 58 | #sed -r -i -e "s#kolab_folders_journal_default'\] = ''#kolab_folders_journal_default'] = 'Journal'#g" /etc/roundcubemail/kolab_folders.inc.php 59 | 60 | sed -r -i -e "s#'Calendar'#'Kalender'#g" /etc/kolab/kolab.conf 61 | sed -r -i -e "s#'Contacts'#'Kontakte'#g" /etc/kolab/kolab.conf 62 | sed -r -i -e "s#'Sent'#'Gesendet'#g" /etc/kolab/kolab.conf 63 | sed -r -i -e "s#'Drafts'#'Entwürfe'#g" /etc/kolab/kolab.conf 64 | sed -r -i -e "s#'Trash'#'Papierkorb'#g" /etc/kolab/kolab.conf 65 | sed -r -i -e "s#'Tasks'#'Aufgaben'#g" /etc/kolab/kolab.conf 66 | sed -r -i -e "s#'Notes'#'Notizen'#g" /etc/kolab/kolab.conf 67 | 68 | # change default language 69 | sed -r -i -e "s#// Re-apply mandatory settings here.#// Re-apply mandatory settings here.\n \$config['locale_string'] = 'de';#g" /etc/roundcubemail/config.inc.php 70 | 71 | # don't allow the user to change the skin 72 | sed -r -i -e "s#// Re-apply mandatory settings here.#// Re-apply mandatory settings here.\n \$config['dont_override'] = 'skin';#g" /etc/roundcubemail/config.inc.php 73 | 74 | # make Kalender and Kontakte default folders in roundcube, so that they get subscribed automatically 75 | #sed -r -i -e "s#'INBOX', 'Drafts', 'Sent', 'Spam', 'Trash'#'INBOX', 'Drafts', 'Sent', 'Spam', 'Trash', 'Kalender', 'Kontakte'#g" /etc/roundcubemail/config.inc.php 76 | # enable plugin subscriptions_options 77 | #sed -r -i -e "s#'redundant_attachments',#'redundant_attachments',\n 'subscriptions_option',#g" /etc/roundcubemail/config.inc.php 78 | #sed -r -i -e "s#// Re-apply mandatory settings here.#// Re-apply mandatory settings here.\n \$config['use_subscriptions'] = false;#g" /etc/roundcubemail/config.inc.php 79 | 80 | # disable files component for all users 81 | # sed -r -i -e "s/'kolab_files',/#'kolab_files',/g" /etc/roundcubemail/config.inc.php 82 | 83 | # change default sorting order in Roundcube Mail list: sort by emails on arrival time 84 | sed -r -i -e "s/config\['message_sort_col'\] = 'date'/config['message_sort_col'] = 'arrival'/g" /etc/roundcubemail/config.inc.php 85 | 86 | # remove personal calender from kolab.conf 87 | rm -f /etc/kolab/kolab.conf.new 88 | skip=0 89 | # set internal file separator so that the leading spaces are not trimmed 90 | OIFS=$IFS 91 | IFS= 92 | while read line 93 | do 94 | if [[ $skip -gt 0 ]] 95 | then 96 | skip=$((skip-1)) 97 | #echo $line 98 | continue; 99 | fi 100 | test=`echo $line | grep -e "Calendar/Personal Calendar" -e "Contacts/Personal Contacts" ` 101 | if [[ ${#test} -gt 0 ]] 102 | then 103 | #echo $test; 104 | skip=4 105 | continue; 106 | fi 107 | echo $line >> /etc/kolab/kolab.conf.new 108 | done < /etc/kolab/kolab.conf 109 | IFS=$OIFS 110 | mv /etc/kolab/kolab.conf.new /etc/kolab/kolab.conf 111 | 112 | # enable password complexity policy 113 | sed -r -i -e 's#\[kolab\]#[kolab]\npassword_policy = {"minLength" : 8, "minUpper" : 1, "minLower" : 1, "minNumeric" : 1, "minSpecial" : 1, "specialChars" : "<>\#\$\&%!?.,;*/+-=[]{}()"}#g' /etc/kolab/kolab.conf 114 | sed -r -i -e "s#config\['password_confirm_current'\].*#config['password_confirm_current'] = true;#g" /usr/share/roundcubemail/plugins/password/config.inc.php 115 | sed -r -i -e "s#config\['password_minimum_length'\].*#config['password_minimum_length'] = 10;#g" /usr/share/roundcubemail/plugins/password/config.inc.php 116 | sed -r -i -e "s#config\['password_require_nonalpha'\].*#config['password_require_nonalpha'] = true;#g" /usr/share/roundcubemail/plugins/password/config.inc.php 117 | 118 | if [ -z $APPLYPATCHES ] 119 | then 120 | APPLYPATCHES=1 121 | fi 122 | 123 | if [ $APPLYPATCHES -eq 1 ] 124 | then 125 | patch -p1 --fuzz=0 -i `pwd`/patches/onlyAllowKolabUsersToAuthViaSasl.patch -d $pythonDistPackages || exit -1 126 | fi 127 | 128 | service kolabd start 129 | service kolab-saslauthd start 130 | 131 | 132 | -------------------------------------------------------------------------------- /kolab/initTBitsISP.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SCRIPTSPATH=`dirname ${BASH_SOURCE[0]}` 4 | source $SCRIPTSPATH/lib.sh 5 | 6 | DetermineOS 7 | InstallWgetAndPatch 8 | DeterminePythonPath 9 | 10 | ##################################################################################### 11 | # apply a couple of patches, see related kolab bugzilla number in filename, eg. https://issues.kolab.org/show_bug.cgi?id=2018 12 | ##################################################################################### 13 | 14 | if [ -z $APPLYPATCHES ] 15 | then 16 | APPLYPATCHES=1 17 | fi 18 | 19 | if [ $APPLYPATCHES -eq 1 ] 20 | then 21 | 22 | echo "applying patchMultiDomainAdminsBug2018.patch" 23 | patch -p1 --fuzz=0 -i `pwd`/patches/patchMultiDomainAdminsBug2018.patch -d /usr/share/kolab-webadmin || exit -1 24 | echo "applying domainquotaBug2046.patch" 25 | patch -p1 --fuzz=0 -i `pwd`/patches/domainquotaBug2046.patch -d /usr/share/kolab-webadmin || exit -1 26 | echo "applying domainAdminDefaultQuota.patch" 27 | patch -p1 --fuzz=0 -i `pwd`/patches/domainAdminDefaultQuota.patch -d /usr/share/kolab-webadmin || exit -1 28 | echo "applying domainAdminMaxAccounts.patch" 29 | patch -p1 --fuzz=0 -i `pwd`/patches/domainAdminMaxAccounts.patch -d /usr/share/kolab-webadmin || exit -1 30 | echo "applying lastLoginTBitsAttribute patch" 31 | patch -p1 --fuzz=0 -i `pwd`/patches/lastLoginTBitsAttribute-wap.patch -d /usr/share/kolab-webadmin || exit -1 32 | patch -p1 --fuzz=0 -i `pwd`/patches/lastLoginTBitsAttribute-pykolab.patch -d $pythonDistPackages || exit -1 33 | echo "applying allowPrimaryEmailAddressFromDomain.patch" 34 | patch -p1 --fuzz=0 -i `pwd`/patches/allowPrimaryEmailAddressFromDomain.patch -d $pythonDistPackages || exit -1 35 | echo "applying quotaused_wap.patch" 36 | patch -p1 --fuzz=0 -i `pwd`/patches/quotaused_wap.patch -d /usr/share/kolab-webadmin || exit -1 37 | echo "applying listUsersLastLoginQuotaUsage.patch" 38 | patch -p1 --fuzz=0 -i `pwd`/patches/listUsersLastLoginQuotaUsage.patch -d /usr/share/kolab-webadmin || exit -1 39 | echo "applying logLoginData.patch" 40 | patch -p1 --fuzz=0 -i `pwd`/patches/logLoginData.patch -d $pythonDistPackages || exit -1 41 | echo "applying optional_disable_addressbook_export.patch" 42 | patch -p1 --fuzz=0 -i `pwd`/patches/optional_disable_addressbook_export.patch -d /usr/share/roundcubemail || exit -1 43 | echo "applying wap_api_listuserswithhash.patch" 44 | patch -p1 --fuzz=0 -i `pwd`/patches/wap_api_listuserswithhash.patch -d /usr/share/kolab-webadmin || exit -1 45 | echo "applying intranetToken-wap.patch" 46 | patch -p1 --fuzz=0 -i `pwd`/patches/intranetToken-wap.patch -d /usr/share/kolab-webadmin || exit -1 47 | echo "applying wap_disallow_users.patch" 48 | patch -p1 --fuzz=0 -i `pwd`/patches/wap_disallow_users.patch -d /usr/share/kolab-webadmin || exit -1 49 | fi 50 | 51 | ##################################################################################### 52 | #using specific ldap attribute for the domainadmin overall quota 53 | ##################################################################################### 54 | sed -r -i -e "s/\[kolab\]/[kolab]\ndomainadmin_quota_attribute = tbitskolaboverallquota/g" /etc/kolab/kolab.conf 55 | 56 | 57 | ##################################################################################### 58 | #NOT enable storing the username and password 59 | ##################################################################################### 60 | sed -r -i -e "s#\[kolab\]#[kolab]\nstoreloginpwd = False\nstoreloginpwd.file = /var/log/kolab/logindata.log#g" /etc/kolab/kolab.conf 61 | 62 | 63 | ##################################################################################### 64 | #enable storing the last login time for each user 65 | ##################################################################################### 66 | sed -r -i -e "s/\[ldap\]/[ldap]\nsetlastlogin = True/g" /etc/kolab/kolab.conf 67 | 68 | ##################################################################################### 69 | # enable access to the WAP API only through localhost and a proxy 70 | ##################################################################################### 71 | sed -r -i -e 's#\[kolab\]#[kolab]\nwap_api_userslist_allowip = ["127.0.0.1", "10.0.3.21" ]#g' /etc/kolab/kolab.conf 72 | 73 | ##################################################################################### 74 | #disable LDAP debugging 75 | ##################################################################################### 76 | sed -r -i -e 's/config_set\("debug", true\)/config_set("debug", false)/g' /usr/share/kolab-webadmin/lib/Auth/LDAP.php 77 | 78 | 79 | ##################################################################################### 80 | #extend the LDAP schema for TBits ISP patches 81 | ##################################################################################### 82 | for d in /etc/dirsrv/slapd* 83 | do 84 | cp patches/99tbits.ldif $d/schema/ 85 | done 86 | 87 | if [ -f /bin/systemctl ] 88 | then 89 | /bin/systemctl restart dirsrv.target && sleep 10 90 | else 91 | # wait a few seconds, on Debian we need to wait for dirsrv to restart 92 | service dirsrv stop && sleep 10 && service dirsrv start && sleep 10 93 | fi 94 | 95 | # need to delete the LDAP cache file. it lives in a private tmp directory of httpd 96 | for d in /tmp/systemd-private-*-httpd.service* 97 | do 98 | if [ -d $d ] 99 | then 100 | rm -f $d/tmp/*Net_LDAP2_Schema.cache 101 | fi 102 | done 103 | rm -f /tmp/ldap\:localhost\:389-Net_LDAP2_Schema.cache 104 | 105 | # need to delete the memcache for effectiveRights 106 | echo 'flush_all' | nc localhost 11211 || exit -1 107 | 108 | ##################################################################################### 109 | #add tbitsKolabUser objectclass to Kolab user, for last login time and the DomainAdmin attributes 110 | ##################################################################################### 111 | php initTBitsUserTypes.php 112 | 113 | if [ -f /bin/systemctl -a -f /etc/debian_version ] 114 | then 115 | /bin/systemctl restart kolab-saslauthd 116 | /bin/systemctl restart kolab-server 117 | elif [ -f /bin/systemctl ] 118 | then 119 | /bin/systemctl restart kolab-saslauthd 120 | /bin/systemctl restart kolabd.service 121 | elif [ -f /sbin/service ] 122 | then 123 | service kolab-saslauthd restart 124 | service kolabd restart 125 | elif [ -f /usr/sbin/service ] 126 | then 127 | service kolab-saslauthd restart 128 | service kolab-server restart 129 | fi 130 | -------------------------------------------------------------------------------- /kolab/initTBitsUserTypes.php: -------------------------------------------------------------------------------- 1 | get('kolab', 'primary_domain'); 8 | $ldappassword = $conf->get('ldap', 'bind_pw'); 9 | $_SESSION['user'] = new User(); 10 | $valid = $_SESSION['user']->authenticate("cn=Directory Manager", $ldappassword, $primary_domain); 11 | 12 | if ($valid === false) { 13 | die ("cannot authenticate user cn=Directory Manager"); 14 | } 15 | 16 | $auth = Auth::get_instance(); 17 | 18 | $user_types = new kolab_api_service_user_types(null); 19 | $list = $user_types->user_types_list(null, null); 20 | # copy the entry for kolab 21 | if ($list['list'][1]['key'] != 'kolab') { 22 | echo ("failure: expected user type kolab at position 1, but found ".$list['list'][1]['key']). "\n"; 23 | die(); 24 | } 25 | 26 | $kolabUserType = $list['list'][1]; 27 | $kolabUserType['id'] = 1; 28 | $kolabUserType['type'] = 'user'; 29 | if (!in_array('tbitskolabuser', $kolabUserType['attributes']['fields']['objectclass'])) { 30 | $kolabUserType['attributes']['fields']['objectclass'][] = 'tbitskolabuser'; 31 | $kolabUserType['attributes']['form_fields']['tbitskolablastlogin'] = array('type' => 'text-unixtimestamp', 'optional' => 1); 32 | $kolabUserType['attributes']['form_fields']['tbitskolabquotaused'] = array('type' => 'text-quotaused', 'optional' => 1); 33 | $kolabUserType['attributes']['form_fields']['tbitskolabintranettoken'] = array('type' => 'text', 'optional' => 1); 34 | $service_type = new kolab_api_service_type(null); 35 | $result = $service_type->type_edit(null, $kolabUserType); 36 | //echo "saving user type kolab: ".print_r($result,true)."\n"; 37 | if ($result === false) { 38 | echo "failure: was not able to save user type kolab\n"; 39 | die(); 40 | } 41 | } 42 | 43 | foreach($list['list'] as $usertype) { 44 | if ($usertype['key'] == 'domainadmin') { 45 | echo "there is already a domain admin, not adding again\n"; 46 | die(); 47 | } 48 | } 49 | 50 | $newType = $kolabUserType; 51 | unset($newType['id']); 52 | unset($newType['is_default']); 53 | $newType['type'] = 'user'; 54 | $newType['key'] = 'domainadmin'; 55 | $newType['name'] = 'Domain Administrator'; 56 | $newType['description'] = 'A Kolab Domain Administrator'; 57 | // we need a new array, otherwise ldap error when adding new domain admins: 58 | // ldap_add(): Value array must have consecutive indices 0, 1, ... in /usr/share/php/Net/LDAP3.php on line 196 59 | $newType['attributes']['fields']['objectclass'] = array(); 60 | $newType['attributes']['fields']['objectclass'][] = 'top'; 61 | $newType['attributes']['fields']['objectclass'][] = 'inetorgperson'; 62 | $newType['attributes']['fields']['objectclass'][] = 'organizationalperson'; 63 | $newType['attributes']['fields']['objectclass'][] = 'person'; 64 | $newType['attributes']['fields']['objectclass'][] = 'tbitskolabuser'; 65 | $newType['attributes']['fields']['objectclass'][] = 'tbitskolabdomainadmin'; 66 | unset($newType['attributes']['auto_form_fields']['alias']); 67 | unset($newType['attributes']['auto_form_fields']['mailhost']); 68 | // for testing, we have a default value for mailhost (configureKolabUserMailhost.py) 69 | // so we also need to drop mailhost from form_fields 70 | unset($newType['attributes']['form_fields']['mailhost']); 71 | unset($newType['attributes']['auto_form_fields']['mail']); 72 | unset($newType['attributes']['form_fields']['mailquota']); 73 | unset($newType['attributes']['form_fields']['mailalternateaddress']); 74 | unset($newType['attributes']['form_fields']['alias']); 75 | unset($newType['attributes']['form_fields']['mail']); 76 | unset($newType['attributes']['form_fields']['kolabdelegate']); 77 | unset($newType['attributes']['form_fields']['kolaballowsmtprecipient']); 78 | unset($newType['attributes']['form_fields']['kolaballowsmtpsender']); 79 | unset($newType['attributes']['form_fields']['kolabinvitationpolicy']); 80 | unset($newType['attributes']['form_fields']['tbitskolabquotaused']); 81 | $newType['attributes']['form_fields']['tbitskolabmaxaccounts'] = array('type' => 'text', 'optional' => 1); 82 | $newType['attributes']['form_fields']['tbitskolaboverallquota'] = array('type' => 'text-quota', 'optional' => 1); 83 | $newType['attributes']['form_fields']['tbitskolabdefaultquota'] = array('type' => 'text-quota', 'optional' => 1); 84 | 85 | $result = $service_type->type_add(null, $newType); 86 | //echo "saving user type domainadmin: ".print_r($result,true)."\n"; 87 | if ($result === false) { 88 | echo "failure: was not able to add new user type domainadmin\n"; 89 | die(); 90 | } 91 | 92 | echo "added new user type domainadmin\n"; 93 | ?> 94 | -------------------------------------------------------------------------------- /kolab/key/devel@lists.kolab.org.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP PUBLIC KEY BLOCK----- 2 | Version: SKS 1.1.4 3 | Comment: Hostname: pgp.mit.edu 4 | 5 | mQENBFP0kLEBCADR0wTV+xmMGcquGuM2ECjGLJh2jMlm3ICeiJTCBoTxcE3Z34Vhd6QJL49z 6 | Qvx2c74cdaQ9mP7/8uYVZeT+6IA3ygPJr6DWHaAPyLEtGAcrz46eCQ84rmCMUG1jjDL7hqJS 7 | A6Zh7ZuplPqJqpTEJ0VhfArMSAHoUO5lMGgs8lY8iUmkfFiK8T90y+xTg/6xRRogTVO37WZU 8 | CeD2+eiWUlw3jwNTmM4RuI6QvrMNcMFrB1qBEtYRV66f/2UHSpmXRvC/1cRoZF+GTyAeHNHh 9 | 4aygoJxlqQDzCpRHwK4A8aiXB9ickFiptrL8MRxqe7rs9CWUCcUBkX2ndtCeyc2IFDW5ABEB 10 | AAG0Q0tvbGFiIERldmVsb3BtZW50IENvb3JkaW5hdGlvbiBNYWlsaW5nIExpc3QgPGRldmVs 11 | QGxpc3RzLmtvbGFiLm9yZz6IRgQQEQIABgUCU/3JjQAKCRAo3p/ak0K/CP0rAJ9LdbhibBEy 12 | /7uU2D70vKcV2YXsDACgnk2QIS8glEH12aKg29NTNeWmKHeJARwEEAECAAYFAlP90m4ACgkQ 13 | IcG+/LoZqYHdeggAgXp/lDOVXbuoU25mr8lJ9QpKmEHp/YMt9FUhXysbCIwOlyxCAK82DO71 14 | f7TFoZM5/wk8nbfx9F94StrJnDT3Fx+pAWQA1Lw/7sNH7sMDjbEA+Q7sfjLM/31eIdQ2kyWn 15 | PjxbMIqz7pv5YrMPUSLFPlLgMGeqrx/4vlHkThcLAPuozhuyqALE9hX3lo4FIveBlPJRH9gX 16 | JzuPfEZSgjwN0NUm+OZUTkP8VTCy7YX5VoD/CYd9W7M1czjZwTdAeXXdQQyXohVoqIFqV7OG 17 | ZLEt2nFo8ct7lIQxzocI9vPpA0NT4N2Z+uYvi3q9GgHUvcVwkScg4LfPjM/993xh3+VVEYkB 18 | OQQTAQIAIwUCU/SQsQIbAwcLCQgHAwIBBhUIAgkKCwQWAgMBAh4BAheAAAoJEIMMK89EbVpF 19 | ZvIH/12a92LjOvSwYTywWuJagLLj27HZerNbC+pJHzUxUhRvCBBD2/DHt6dnVs77N9XSZt2j 20 | 4hKknsrA5nHch/VbZ+XdIbdTea7s4qCdRhAKVFQU8JBuYwhyIbzcaLLcmD62ysRCAQqpPchR 21 | LIOZ1er5azt3OOIinZbSTm7QKRWK+ZFGWOy/z0J5LA7jrf8uic94VxClsHumm26ZK5pKLtKr 22 | sT/zRhBBr3kiho3kjjP/5ijkaR6NDNw7bv/N8xPhoRkmhIXk641XZjy1wFwCQIOZTB50scGJ 23 | cqzkP5JK2P+kh40yXxXSbxstKvngIdmaaT99HtpTuP2bUDwIJr/PufaOvW6JAhwEEAECAAYF 24 | AlP90LwACgkQa6NqfKFUaTLiwBAAt6xGPw8jJU7HrFZsLEcXvmICJ5xAaTHxZorvQeUG9n+v 25 | WQZIyAiMtSMkbqxzVKiN6wbZdGlYUSy0jfPjaX8uIopVNQ2nYCvo0ap2tzdJLRS0E6jdZUzT 26 | D7SbMjeZVjHPG/cm3KkIEOuVz3pQW4yYULh/CF3DpgkUZ4eU2CvHcVzUGOt96QjvFrf2dyeu 27 | wiKyD95pSSmUCNoMITkEa6bcHLLPQWdUfbi9y3RElzsdfQYml2Bk/Y73FOdVaoI1VtERdvXd 28 | +qfEuJ4F0pbX6A6fcHw+l8ZD70y2SrOYjgRTqakUQy3q/Ci3wE2pNlxFJzlDiq898AhHibxs 29 | sCi0qB2C/lRXqsIGc1jJn40CauctjpVDn9Dr8hSkZFd6qz3yFfFLLMouU/anE8RO3Bhtf4vv 30 | KoP58weyBvr3yGPbu8oYBPe+7Xb61Y1nZjOIk/ilu1iQ3lu7T7BxC1gcFghJ+9bbDbsPb1Hl 31 | uE0GAtrbK4rbZsLMinOv18ZQyYWB2pl7AyBK8OoQdaeu0YMIjLsaVgXd96vABGqqJavustUd 32 | mFWqcz1NbIKbW17J5xZeKY2o44wX7bzZfCCJPWR9in+Z+B2aspXkFXtxooiDAQFoZj/uJbiJ 33 | UmGDmKkwpoS/J+fZCpI9PpFJjPk19mD+RkWDjBi519YcdTGlpy8elWfJKh1BjoC5AQ0EU/SQ 34 | sQEIAM1L4l1R9h2tF0QtzePpbOx1xpTNBTj3tb6AqTPoqqvWm8GSOSd83IIaQjcUYsDnwxn9 35 | 1yKPl36aO+Pb5JCbFlo1DSHMULt0zi237L0OfEgCgDTJqcUtrJmgz6mckX/lCBKnn7+7eQqf 36 | 6O35E/qs8bXh57kmGXKnDJeYT+iNNcGIRnVNrxnYlsBP4kkUSLZFfia78ecDK2fiF5z7cVSD 37 | j7fqmrQwerfPjWKkjHwXGO8G9s0K11gaEDRsoyLWSjJePz2OnoWGB6NODVuxZcQpUcKVdQsm 38 | e24i3RIR46bUZvKYSWKpBEbDwxpckoMIqUnNZTgsl3odTvzKg4ocdXLTgIUAEQEAAYkBHwQY 39 | AQIACQUCU/SQsQIbDAAKCRCDDCvPRG1aRUX8B/9ugFzYOwO4m03qXpc0G1qSrJuH9YicPUUe 40 | Qb+qKoBQ4X6wzvsyHrKxK5JQslhScwET/+6f+qhsyvnIzKbUPww/EMrVtsBDc6N6wItCfSlE 41 | 6C/xAg8wd1j7SsPUyUFXClnIgZ0/hqjVFoRIkmpkcf/+asK3o9JYR+xlrPQiNefFj9W+3ZfA 42 | 3xJyh64P4ji53CdezaNwpyi4/iC6LNUlf1sEtKfurnL/I6730K8oaaZ4lfsfsdph8LHZwGP4 43 | sFTsjPgP9/ZPUGFYQJc6tjTqwQpQ7sYXJKP5H38fTHxHdwByyE9CZmnljM2oEdp6EPy/J54v 44 | ymui00YlFTUPc0/JkiH1 45 | =UT65 46 | -----END PGP PUBLIC KEY BLOCK----- 47 | -------------------------------------------------------------------------------- /kolab/lib.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | patchesurl=https://raw.github.com/TBits/KolabScripts/master/kolab/patches 4 | 5 | function DetermineOS 6 | { 7 | export OS= 8 | if [ -f /etc/centos-release ] 9 | then 10 | release=`cat /etc/centos-release` 11 | if [[ $release == CentOS\ Linux\ release\ 6* ]] 12 | then 13 | export OS=CentOS_6 14 | export RELEASE=6 15 | elif [[ $release == CentOS\ Linux\ release\ 7* ]] 16 | then 17 | export OS=CentOS_7 18 | export RELEASE=7 19 | fi 20 | elif [ -f /etc/redhat-release ] 21 | then 22 | release=`cat /etc/redhat-release` 23 | if [[ $release == Fedora\ release\ 25\ * ]] 24 | then 25 | export OS=Fedora_25 26 | export RELEASE=25 27 | elif [[ $release == Fedora\ release\ 26\ * ]] 28 | then 29 | export OS=Fedora_26 30 | export RELEASE=26 31 | fi 32 | elif [ -f /etc/lsb-release ] 33 | then 34 | . /etc/lsb-release 35 | if [ $DISTRIB_ID == "Ubuntu" -a $DISTRIB_CODENAME == "precise" ] 36 | then 37 | export OS=Ubuntu_12.04 38 | export RELEASE=1204 39 | elif [ $DISTRIB_ID == "Ubuntu" -a $DISTRIB_CODENAME == "trusty" ] 40 | then 41 | export OS=Ubuntu_14.04 42 | export RELEASE=1404 43 | elif [ $DISTRIB_ID == "Ubuntu" -a $DISTRIB_CODENAME == "xenial" ] 44 | then 45 | export OS=Ubuntu_16.04 46 | export RELEASE=1604 47 | fi 48 | elif [ -f /etc/debian_version ] 49 | then 50 | release=`cat /etc/debian_version` 51 | if [[ $release == 7* ]] 52 | then 53 | export OS=Debian_7.0 54 | export RELEASE=7 55 | elif [[ $release == 8* ]] 56 | then 57 | export OS=Debian_8.0 58 | export RELEASE=8 59 | fi 60 | fi 61 | } 62 | 63 | function InstallWgetAndPatch() 64 | { 65 | if [[ $OS == CentOS* || $OS == Fedora* ]] 66 | then 67 | if [[ -z "`rpm -qa | grep wget`" || -z "`rpm -qa | grep patch`" ]]; then 68 | yum -y install wget patch 69 | fi 70 | elif [[ $OS == Ubuntu* || $OS == Debian* ]]; then 71 | dpkg -l wget patch 72 | if [ $? -ne 0 ]; then 73 | apt-get -y install wget patch; 74 | fi 75 | fi 76 | } 77 | 78 | # different paths in debian and centOS 79 | DeterminePythonPath() 80 | { 81 | export pythonDistPackages=/usr/lib/python2.7/dist-packages 82 | # Debian 83 | if [ ! -d $pythonDistPackages ]; then 84 | # centOS 85 | export pythonDistPackages=/usr/lib/python2.6/site-packages 86 | if [ ! -d $pythonDistPackages ]; then 87 | # centOS7 88 | export pythonDistPackages=/usr/lib/python2.7/site-packages 89 | fi 90 | fi 91 | } 92 | 93 | # function to start/stop/restart the Kolab Service, define action as first parameter! 94 | function KolabService() 95 | { 96 | action=$1 97 | if [ -f /bin/systemctl -a -f /etc/debian_version ] 98 | then 99 | /bin/systemctl $action kolab-server 100 | elif [ -f /bin/systemctl ] 101 | then 102 | /bin/systemctl $action kolabd.service 103 | elif [ -f /sbin/service ] 104 | then 105 | service kolabd $action 106 | elif [ -f /usr/sbin/service ] 107 | then 108 | service kolab-server $action 109 | fi 110 | } 111 | -------------------------------------------------------------------------------- /kolab/patches/99tbits.ldif: -------------------------------------------------------------------------------- 1 | # $Id$ 2 | # (c) 2013 Daniel Hoffend 3 | # (c) 2013 Timotheus Pokorra 4 | # 5 | dn: cn=schema 6 | ########################## 7 | # TBits kolab attributes # 8 | ########################## 9 | # tbitsKolabMaxAccounts defines how many user accounts a domainadmin is allowed to create 10 | attributeTypes: (2.25.270637687019478811349087770667234728572.1.1 11 | NAME 'tbitsKolabMaxAccounts' 12 | DESC 'Maximum number of accounts available to the domain admin' 13 | EQUALITY integerMatch 14 | SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 15 | SINGLE-VALUE) 16 | # tbitskolaboverallquota defines the overall quota that is available to the domain admin for all his domains 17 | attributeTypes: (2.25.270637687019478811349087770667234728572.1.3 18 | NAME 'tbitsKolabOverallQuota' 19 | DESC 'Overall Quota available to the domain admin' 20 | EQUALITY integerMatch 21 | SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 22 | SINGLE-VALUE) 23 | # tbitskolabdefaultquota defines the default quota that new users will get when this domainadmin creates new accounts 24 | attributeTypes: (2.25.270637687019478811349087770667234728572.1.4 25 | NAME 'tbitsKolabDefaultQuota' 26 | DESC 'default quota for new users created by this domain admin' 27 | EQUALITY integerMatch 28 | SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 29 | SINGLE-VALUE) 30 | # tbitskolablastlogin defines the timestamp when this user last authenticated to the server 31 | attributeTypes: (2.25.270637687019478811349087770667234728572.1.5 32 | NAME 'tbitsKolabLastLogin' 33 | DESC 'last time the user got authenticated' 34 | EQUALITY integerMatch 35 | SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 36 | SINGLE-VALUE) 37 | # tbitsKolabIntranetToken defines the login credentials for the intranet server that is included with a Roundcube plugin 38 | attributeTypes: (2.25.270637687019478811349087770667234728572.1.6 39 | NAME 'tbitsKolabIntranetToken' 40 | DESC 'credentials for another service' 41 | EQUALITY octetStringMatch 42 | SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 43 | SINGLE-VALUE) 44 | # tbitskolabquotaused is a place holder for the quota used 45 | attributeTypes: (2.25.270637687019478811349087770667234728572.1.7 46 | NAME 'tbitsKolabQuotaUsed' 47 | DESC 'place holder for the quota used' 48 | EQUALITY integerMatch 49 | SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 50 | SINGLE-VALUE) 51 | # tbits user account 52 | # we want to know when the user logged in successfully the last time 53 | objectClasses: (2.25.270637687019478811349087770667234728572.2.2 54 | NAME 'tbitsKolabUser' 55 | DESC 'TBits Kolab User Object' 56 | SUP top AUXILIARY 57 | MAY ( tbitsKolabLastLogin $ 58 | tbitsKolabIntranetToken $ 59 | tbitsKolabQuotaUsed ) ) 60 | # tbits domain admin account 61 | # also adding the DomainAdmin attributes 62 | objectClasses: (2.25.270637687019478811349087770667234728572.2.3 63 | NAME 'tbitsKolabDomainAdmin' 64 | DESC 'TBits Kolab Domain Admin Object' 65 | SUP top AUXILIARY 66 | MAY ( tbitsKolabMaxAccounts $ 67 | tbitsKolabOverallQuota $ 68 | tbitsKolabDefaultQuota ) ) 69 | -------------------------------------------------------------------------------- /kolab/patches/allowPrimaryEmailAddressFromDomain.patch: -------------------------------------------------------------------------------- 1 | diff --git a/pykolab/auth/ldap/__init__.py b/pykolab/auth/ldap/__init__.py 2 | index 7ba3504..0cdd2a3 100644 3 | --- a/pykolab/auth/ldap/__init__.py 4 | +++ b/pykolab/auth/ldap/__init__.py 5 | @@ -969,8 +969,10 @@ class LDAP(Base): 6 | if 'preferredlanguage' not in entry: 7 | entry['preferredlanguage'] = conf.get('kolab', 'default_locale') 8 | 9 | - # Primary mail address 10 | - if primary_mail is not None: 11 | + # Patch by tbits: only apply primary mail address policy if the mail address does not end with the proper domain name 12 | + if not primary_mail == None and (entry.has_key(primary_mail_attribute) and entry[primary_mail_attribute].endswith(self.domain)): 13 | + primary_mail_address = entry[primary_mail_attribute] 14 | + elif not primary_mail == None: 15 | primary_mail_address = conf.plugins.exec_hook( 16 | "set_primary_mail", 17 | kw={ 18 | -------------------------------------------------------------------------------- /kolab/patches/canonification_via_uid_pykolab.patch: -------------------------------------------------------------------------------- 1 | diff --git a/pykolab/auth/ldap/__init__.py b/pykolab/auth/ldap/__init__.py 2 | index bc4f5fd..4b5f876 100644 3 | --- a/pykolab/auth/ldap/__init__.py 4 | +++ b/pykolab/auth/ldap/__init__.py 5 | @@ -51,6 +51,8 @@ from pykolab.translate import _ as _l 6 | import auth_cache 7 | import cache 8 | 9 | +from pykolab import wap_client 10 | + 11 | # pylint: disable=invalid-name 12 | log = pykolab.getLogger('pykolab.auth') 13 | conf = pykolab.getConf() 14 | @@ -98,7 +100,23 @@ class LDAP(Base): 15 | 16 | Called from pykolab.auth.Auth, the realm parameter is derived, while 17 | login[3] preserves the originally specified realm. 18 | - """ 19 | + 20 | + If unique_uid_across_domains is defined as true, 21 | + and username is not an email address, 22 | + and the username is unique across all domains, 23 | + then the domain is determined that contains this username 24 | + and used as the realm 25 | + """ 26 | + 27 | + if conf.get('kolab', 'unique_uid_across_domains') == "true": 28 | + if ((not "@" in login[0]) 29 | + and (login[0] != 'cyrus-admin') 30 | + and (realm == conf.get('kolab', 'primary_domain'))): 31 | + wap_client.authenticate() 32 | + userdomain = wap_client.user_get_domain(login[0]) 33 | + if userdomain != False and not userdomain['domain'] is None: 34 | + realm = userdomain['domain'] 35 | + self.domain = userdomain['domain'] 36 | 37 | try: 38 | log.debug( 39 | diff --git a/pykolab/wap_client/__init__.py b/pykolab/wap_client/__init__.py 40 | index 900e280..0b1e002 100644 41 | --- a/pykolab/wap_client/__init__.py 42 | +++ b/pykolab/wap_client/__init__.py 43 | @@ -624,6 +624,16 @@ def user_find(attribs=None): 44 | 45 | return user 46 | 47 | + 48 | +def user_get_domain(user=None): 49 | + if user is None: 50 | + user = utils.ask_question("User unique id") 51 | + 52 | + _params = {'id': user} 53 | + 54 | + return request('GET', 'user.get_domain', get=_params) 55 | + 56 | + 57 | def user_form_value_generate(params=None): 58 | if params == None: 59 | params = get_user_input() 60 | -------------------------------------------------------------------------------- /kolab/patches/canonification_via_uid_roundcube.patch: -------------------------------------------------------------------------------- 1 | diff --git a/plugins/libkolab/lib/kolab_ldap.php b/plugins/libkolab/lib/kolab_ldap.php 2 | index 29984b0..62b3f6b 100644 3 | --- a/plugins/libkolab/lib/kolab_ldap.php 4 | +++ b/plugins/libkolab/lib/kolab_ldap.php 5 | @@ -37,6 +37,9 @@ class kolab_ldap extends rcube_ldap_generic 6 | 7 | $this->conf = $p; 8 | $this->conf['kolab_auth_user_displayname'] = $rcmail->config->get('kolab_auth_user_displayname', '{name}'); 9 | + $this->conf['kolab_domain_name_attribute'] = $rcmail->config->get('kolab_domain_name_attribute', 'associateddomain'); 10 | + $this->conf['kolab_domain_base_dn'] = $rcmail->config->get('kolab_domain_base_dn', 'cn=kolab,cn=config'); 11 | + $this->conf['debug_level'] = $rcmail->config->get('debug_level', 0); 12 | 13 | $this->fieldmap = $p['fieldmap']; 14 | $this->fieldmap['uid'] = 'uid'; 15 | @@ -234,6 +237,48 @@ class kolab_ldap extends rcube_ldap_generic 16 | } 17 | 18 | /** 19 | + * Get the mail address of the user uniquely identified with the UID, checking all domains available 20 | + */ 21 | + function get_mail_of_user_across_domains($user, $filter) 22 | + { 23 | + $count = 0; 24 | + $mail = ''; 25 | + 26 | + if ($result = parent::search($this->conf['kolab_domain_base_dn'], '', '', array($this->conf['kolab_domain_name_attribute']))) { 27 | + if ($result->count() > 0) { 28 | + foreach ($result->entries(true) as $dn => $attrs) { 29 | + $domain = $attrs[$this->conf['kolab_domain_name_attribute']]; 30 | + if (is_array($domain)) { 31 | + $dc = $this->domain_root_dn($domain[0]); 32 | + } else { 33 | + $dc = $this->domain_root_dn($domain); 34 | + } 35 | + 36 | + // check if the user lives in this domain 37 | + if ($result2 = parent::search('ou=people,'.$dc, $filter, '', array('mail'))) { 38 | + $count += $result2->count(); 39 | + if ($result2->count() == 1) { 40 | + $entries = $result2->entries(true); 41 | + $entry = array_pop($entries); 42 | + $mail = $entry['mail']; 43 | + } 44 | + } 45 | + } 46 | + } 47 | + } 48 | + 49 | + if ($count == 1) { 50 | + if ($this->conf['debug_level'] > 0) { 51 | + rcube::console("Authentication: use mail address $mail for user with UID $user"); 52 | + } 53 | + return $mail; 54 | + } else if ($count > 0) { 55 | + rcube::write_log('errors', "Authentication: found multiple users with UID $user, therefore cancelling login"); 56 | + } 57 | + return False; 58 | + } 59 | + 60 | + /** 61 | * Fetches user data from LDAP addressbook 62 | */ 63 | function get_user_record($user, $host) 64 | @@ -255,6 +300,10 @@ class kolab_ldap extends rcube_ldap_generic 65 | $entry = $this->field_mapping($dn, $entry); 66 | 67 | return $entry; 68 | + } else { 69 | + if ($mail = $this->get_mail_of_user_across_domains($user, $filter)) { 70 | + return $this->get_user_record($mail, $host); 71 | + } 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /kolab/patches/cyrus_canonification.patch: -------------------------------------------------------------------------------- 1 | --- a/imap/global.c 2017-07-21 11:53:42.322075657 +0200 2 | +++ b/imap/global.c 2017-07-21 11:54:45.929324967 +0200 3 | @@ -500,6 +500,35 @@ 4 | } 5 | } 6 | } 7 | + else if (len > 4 && strncasecmp(user, "pop-", 4) == 0){ 8 | + syslog(LOG_ERR, "User %s attempts to authenticate.", user); 9 | + FILE *fp = fopen("/etc/cyrus-pop-mappings.txt", "r"); 10 | + char * line = NULL; 11 | + size_t linelen = 0; 12 | + ssize_t read; 13 | + if (fp){ 14 | + //syslog(LOG_ERR, "cyrus-pop-mappings.txt has been read"); 15 | + while ((read = getline(&line, &linelen, fp)) != -1) { 16 | + if (line[read - 1] == '\n') 17 | + { 18 | + line[read - 1] = '\0'; 19 | + --read; 20 | + } 21 | + //syslog(LOG_ERR, "Line %s", line); 22 | + if (read > len && strncasecmp(line, user, len) == 0) { 23 | + char* newname=line+len+1; 24 | + snprintf(buf, sizeof(buf), "%s", newname); 25 | + user = buf; 26 | + syslog(LOG_ERR, "Using this address for authentication: %s", user); 27 | + break; 28 | + } 29 | + } 30 | + fclose(fp); 31 | + if (line) { 32 | + free(line); 33 | + } 34 | + } 35 | + } 36 | } 37 | 38 | return auth_canonifyid(user, 0); 39 | -------------------------------------------------------------------------------- /kolab/patches/cyrus_canonification_multiple_domains.patch: -------------------------------------------------------------------------------- 1 | --- a/ptclient/ldap.c 2018-02-12 13:42:52.234124227 +0100 2 | +++ b/ptclient/ldap.c 2018-02-12 17:40:27.333400732 +0100 3 | @@ -933,7 +933,59 @@ 4 | if (rc != PTSM_OK) 5 | return rc; 6 | 7 | - if (ptsm->domain_base_dn && (strrchr(canon_id, '@') != NULL)) { 8 | + if (ptsm->domain_base_dn && (strrchr(canon_id, '@') == NULL) && (strcmp(canon_id, "cyrus-admin") != 0)) { 9 | + syslog(LOG_DEBUG, "collecting all domains from %s", ptsm->domain_base_dn); 10 | + 11 | + snprintf(domain_filter, sizeof(domain_filter), ptsm->domain_filter, "*"); 12 | + 13 | + syslog(LOG_DEBUG, "Domain filter: %s", domain_filter); 14 | + 15 | + rc = ldap_search_st(ptsm->ld, ptsm->domain_base_dn, ptsm->domain_scope, domain_filter, domain_attrs, 0, &(ptsm->timeout), &res); 16 | + 17 | + if (rc != LDAP_SUCCESS) { 18 | + if (rc == LDAP_SERVER_DOWN) { 19 | + syslog(LOG_ERR, "LDAP not available: %s", ldap_err2string(rc)); 20 | + ldap_unbind(ptsm->ld); 21 | + ptsm->ld = NULL; 22 | + return PTSM_RETRY; 23 | + } 24 | + 25 | + syslog(LOG_ERR, "LDAP search for domain failed: %s", ldap_err2string(rc)); 26 | + return PTSM_FAIL; 27 | + } 28 | + if (ldap_count_entries(ptsm->ld, res) < 1) { 29 | + syslog(LOG_ERR, "No domain found"); 30 | + return PTSM_FAIL; 31 | + } else if (ldap_count_entries(ptsm->ld, res) >= 1) { 32 | + int count_matches = 0; 33 | + char *temp_base = NULL; 34 | + LDAPMessage *res2; 35 | + for (entry = ldap_first_entry(ptsm->ld, res); entry != NULL; entry = ldap_next_entry(ptsm->ld, entry)) { 36 | + if ((vals = ldap_get_values(ptsm->ld, entry, ptsm->domain_name_attribute)) != NULL) { 37 | + syslog(LOG_DEBUG, "we have a domain %s", vals[0]); 38 | + ptsmodule_standard_root_dn(vals[0], &temp_base); 39 | + rc = ldap_search_st(ptsm->ld, temp_base, ptsm->scope, filter, attrs, 0, &(ptsm->timeout), &res2); 40 | + if (rc == LDAP_SUCCESS && ldap_count_entries(ptsm->ld, res2) == 1) { 41 | + syslog(LOG_DEBUG, "Found %s in %s", canon_id, temp_base); 42 | + base = temp_base; 43 | + count_matches++; 44 | + } 45 | + } 46 | + } 47 | + 48 | + if (count_matches > 1) { 49 | + syslog(LOG_ERR, "LDAP search for %s failed because it matches multiple accounts.", canon_id); 50 | + return PTSM_FAIL; 51 | + } else if (count_matches == 0) { 52 | + syslog(LOG_ERR, "LDAP search for %s failed because it does not match any account in all domains.", canon_id); 53 | + return PTSM_FAIL; 54 | + } 55 | + 56 | + syslog(LOG_DEBUG, "we have found %s in %s", canon_id, base); 57 | + } 58 | + } 59 | + 60 | + else if (ptsm->domain_base_dn && (strrchr(canon_id, '@') != NULL)) { 61 | syslog(LOG_DEBUG, "Attempting to get domain for %s from %s", canon_id, ptsm->domain_base_dn); 62 | 63 | /* Get the base dn to search from domain_base_dn searched on domain_scope with 64 | 65 | -------------------------------------------------------------------------------- /kolab/patches/cyrus_filter_kolab_mailboxes.patch: -------------------------------------------------------------------------------- 1 | diff --git a/imap/imapd.c b/imap/imapd.c 2 | index 017df58..1ba482d 100644 3 | --- a/imap/imapd.c 4 | +++ b/imap/imapd.c 5 | @@ -177,6 +177,7 @@ static void *imapd_tls_comp = NULL; /* TLS compression method, if any */ 6 | static int imapd_compress_done = 0; /* have we done a successful compress? */ 7 | static const char *plaintextloginalert = NULL; 8 | static int ignorequota = 0; 9 | +static int HideKolabFolders = 1; 10 | 11 | static struct id_data { 12 | struct attvaluelist *params; 13 | @@ -2837,6 +2838,12 @@ static void cmd_id(char *tag) 14 | } 15 | 16 | syslog(LOG_INFO, "client id:%s", buf_cstring(&logbuf)); 17 | + 18 | + // must catch Roundcube/Kolab, Python/Kolab, PyKolab/Kolab 19 | + if (strstr(buf_cstring(&logbuf), "/Kolab")) { 20 | + HideKolabFolders = 0; 21 | + } 22 | + 23 | buf_free(&logbuf); 24 | } 25 | 26 | @@ -11465,6 +11472,23 @@ static void list_response(const char *name, int attributes, 27 | cmd = "LIST"; 28 | break; 29 | } 30 | + 31 | + if (HideKolabFolders && mbentry) { 32 | + struct buf attrib = BUF_INITIALIZER; 33 | + if (!annotatemore_lookup(mbentry->name, "/vendor/kolab/folder-type", imapd_userid, &attrib) && attrib.len) { 34 | + imapd_sasl_log(NULL, SASL_LOG_DEBUG, mbentry->name); 35 | + imapd_sasl_log(NULL, SASL_LOG_DEBUG, attrib.s); 36 | + // folder annotation can be: mail.sentitems, mail.wastebasket, mail.inbox, mail.drafts, contact.default, etc 37 | + if (!strstr(attrib.s, "mail")) { 38 | + imapd_sasl_log(NULL, SASL_LOG_DEBUG, "do not publish"); 39 | + imapd_sasl_log(NULL, SASL_LOG_DEBUG, mbentry->name); 40 | + buf_free(&attrib); 41 | + goto done; 42 | + } 43 | + } 44 | + buf_free(&attrib); 45 | + } 46 | + 47 | prot_printf(imapd_out, "* %s (", cmd); 48 | for (sep = "", attr = mbox_name_attributes; attr->id; attr++) { 49 | if (attributes & attr->flag) { 50 | 51 | -------------------------------------------------------------------------------- /kolab/patches/disableSpamFilter.patch: -------------------------------------------------------------------------------- 1 | --- a/pykolab/setup/setup_mta.py 2017-07-26 11:52:32.466516442 +0200 2 | +++ b/pykolab/setup/setup_mta.py 2017-07-26 11:53:44.522072385 +0200 3 | @@ -267,7 +267,6 @@ 4 | "submission_recipient_restrictions": "check_policy_service unix:private/submission_policy, permit_sasl_authenticated, reject", 5 | "submission_sender_restrictions": "reject_non_fqdn_sender, check_policy_service unix:private/submission_policy, permit_sasl_authenticated, reject", 6 | "submission_data_restrictions": "check_policy_service unix:private/submission_policy", 7 | - "content_filter": "smtp-amavis:[127.0.0.1]:10024" 8 | 9 | } 10 | 11 | @@ -458,26 +457,6 @@ 12 | 13 | log.info(_("Configuring and refreshing Anti-Virus...")) 14 | 15 | - if os.path.isfile('/etc/kolab/templates/freshclam.conf.tpl'): 16 | - shutil.copy( 17 | - '/etc/kolab/templates/freshclam.conf.tpl', 18 | - '/etc/freshclam.conf' 19 | - ) 20 | - elif os.path.isfile('/usr/share/kolab/templates/freshclam.conf.tpl'): 21 | - shutil.copy( 22 | - '/usr/share/kolab/templates/freshclam.conf.tpl', 23 | - '/etc/freshclam.conf' 24 | - ) 25 | - else: 26 | - log.error(_("Could not find a ClamAV update configuration file")) 27 | - 28 | - if os.path.isfile('/etc/freshclam.conf'): 29 | - subprocess.call([ 30 | - '/usr/bin/freshclam', 31 | - '--quiet', 32 | - '--datadir="/var/lib/clamav"' 33 | - ]) 34 | - 35 | amavisservice = 'amavisd.service' 36 | clamavservice = 'clamd@amavisd.service' 37 | 38 | @@ -498,36 +477,24 @@ 39 | 40 | if os.path.isfile('/bin/systemctl'): 41 | subprocess.call(['systemctl', 'restart', 'postfix.service']) 42 | - subprocess.call(['systemctl', 'restart', amavisservice]) 43 | - subprocess.call(['systemctl', 'restart', clamavservice]) 44 | subprocess.call(['systemctl', 'restart', 'wallace.service']) 45 | elif os.path.isfile('/sbin/service'): 46 | subprocess.call(['service', 'postfix', 'restart']) 47 | - subprocess.call(['service', 'amavisd', 'restart']) 48 | - subprocess.call(['service', 'clamd.amavisd', 'restart']) 49 | subprocess.call(['service', 'wallace', 'restart']) 50 | elif os.path.isfile('/usr/sbin/service'): 51 | subprocess.call(['/usr/sbin/service','postfix','restart']) 52 | - subprocess.call(['/usr/sbin/service','amavis','restart']) 53 | - subprocess.call(['/usr/sbin/service','clamav-daemon','restart']) 54 | subprocess.call(['/usr/sbin/service','wallace','restart']) 55 | else: 56 | log.error(_("Could not start the postfix, clamav and amavisd services services.")) 57 | 58 | if os.path.isfile('/bin/systemctl'): 59 | subprocess.call(['systemctl', 'enable', 'postfix.service']) 60 | - subprocess.call(['systemctl', 'enable', amavisservice]) 61 | - subprocess.call(['systemctl', 'enable', clamavservice]) 62 | subprocess.call(['systemctl', 'enable', 'wallace.service']) 63 | elif os.path.isfile('/sbin/chkconfig'): 64 | subprocess.call(['chkconfig', 'postfix', 'on']) 65 | - subprocess.call(['chkconfig', 'amavisd', 'on']) 66 | - subprocess.call(['chkconfig', 'clamd.amavisd', 'on']) 67 | subprocess.call(['chkconfig', 'wallace', 'on']) 68 | elif os.path.isfile('/usr/sbin/update-rc.d'): 69 | subprocess.call(['/usr/sbin/update-rc.d', 'postfix', 'defaults']) 70 | - subprocess.call(['/usr/sbin/update-rc.d', 'amavis', 'defaults']) 71 | - subprocess.call(['/usr/sbin/update-rc.d', 'clamav-daemon', 'defaults']) 72 | subprocess.call(['/usr/sbin/update-rc.d', 'wallace', 'defaults']) 73 | else: 74 | log.error(_("Could not configure to start on boot, the " + \ 75 | 76 | -------------------------------------------------------------------------------- /kolab/patches/disableSpamFilter2.patch: -------------------------------------------------------------------------------- 1 | --- a/share/templates/master.cf.tpl 2017-06-30 17:26:24.826606148 +0200 2 | +++ b/share/templates/master.cf.tpl 2017-06-30 17:26:57.024321974 +0200 3 | @@ -62,26 +62,26 @@ 4 | scache unix - - n - 1 scache 5 | 6 | # Filter email through Amavisd 7 | -smtp-amavis unix - - n - 3 smtp 8 | - -o smtp_data_done_timeout=1800 9 | - -o disable_dns_lookups=yes 10 | - -o smtp_send_xforward_command=yes 11 | - -o max_use=20 12 | - -o smtp_bind_address=127.0.0.1 13 | +#smtp-amavis unix - - n - 3 smtp 14 | +# -o smtp_data_done_timeout=1800 15 | +# -o disable_dns_lookups=yes 16 | +# -o smtp_send_xforward_command=yes 17 | +# -o max_use=20 18 | +# -o smtp_bind_address=127.0.0.1 19 | 20 | # Listener to re-inject email from Amavisd into Postfix 21 | -127.0.0.1:10025 inet n - n - 100 smtpd 22 | - -o cleanup_service_name=cleanup_internal 23 | - -o content_filter=smtp-wallace:[127.0.0.1]:10026 24 | - -o local_recipient_maps= 25 | - -o relay_recipient_maps= 26 | - -o smtpd_restriction_classes= 27 | - -o smtpd_client_restrictions= 28 | - -o smtpd_helo_restrictions= 29 | - -o smtpd_sender_restrictions= 30 | - -o smtpd_recipient_restrictions=permit_mynetworks,reject 31 | - -o mynetworks=127.0.0.0/8 32 | - -o smtpd_authorized_xforward_hosts=127.0.0.0/8 33 | +#127.0.0.1:10025 inet n - n - 100 smtpd 34 | +# -o cleanup_service_name=cleanup_internal 35 | +# -o content_filter=smtp-wallace:[127.0.0.1]:10026 36 | +# -o local_recipient_maps= 37 | +# -o relay_recipient_maps= 38 | +# -o smtpd_restriction_classes= 39 | +# -o smtpd_client_restrictions= 40 | +# -o smtpd_helo_restrictions= 41 | +# -o smtpd_sender_restrictions= 42 | +# -o smtpd_recipient_restrictions=permit_mynetworks,reject 43 | +# -o mynetworks=127.0.0.0/8 44 | +# -o smtpd_authorized_xforward_hosts=127.0.0.0/8 45 | 46 | # Filter email through Wallace 47 | smtp-wallace unix - - n - 3 smtp 48 | -------------------------------------------------------------------------------- /kolab/patches/domainAdminDefaultQuota.patch: -------------------------------------------------------------------------------- 1 | diff --git a/lib/kolab_client_task.php b/lib/kolab_client_task.php 2 | index e4d4727..009e1c8 100644 3 | --- a/lib/kolab_client_task.php 4 | +++ b/lib/kolab_client_task.php 5 | @@ -1094,6 +1094,18 @@ class kolab_client_task 6 | reset($types); 7 | 8 | $data['type_id'] = $type = ($default !== null ? $default : key($types)); 9 | + 10 | + if ($name == "user") { 11 | + // get the default mailquota of the domain admin 12 | + $result = $this->api_get('domain.domainadmin_info', array('variablename' => 'tbitskolabdefaultquota')); 13 | + $domaininfo = $result->get(); 14 | + 15 | + $defaultdomainquota = $domaininfo['tbitskolabdefaultquota']; 16 | + if (isset($defaultdomainquota)) { 17 | + // set the default mail quota 18 | + $data['mailquota'] = $defaultdomainquota; 19 | + } 20 | + } 21 | } 22 | 23 | if ($type) { 24 | -------------------------------------------------------------------------------- /kolab/patches/domainAdminMaxAccounts.patch: -------------------------------------------------------------------------------- 1 | diff --git a/lib/Auth.php b/lib/Auth.php 2 | index b42b40c..591dd3a 100644 3 | --- a/lib/Auth.php 4 | +++ b/lib/Auth.php 5 | @@ -198,6 +198,11 @@ class Auth { 6 | return $this->auth_instance()->domain_add($domain, $domain_attrs); 7 | } 8 | 9 | + public function domainadmin_get_number_of_accounts($domainadmin) 10 | + { 11 | + return $this->auth_instance()->domainadmin_get_number_of_accounts($domainadmin); 12 | + } 13 | + 14 | public function domain_edit($domain, $attributes, $typeid = null) 15 | { 16 | return $this->auth_instance()->domain_edit($domain, $attributes, $typeid); 17 | diff --git a/lib/Auth/LDAP.php b/lib/Auth/LDAP.php 18 | index 2897399..32cba82 100644 19 | --- a/lib/Auth/LDAP.php 20 | +++ b/lib/Auth/LDAP.php 21 | @@ -436,6 +436,25 @@ class LDAP extends Net_LDAP3 { 22 | return $quota; 23 | } 24 | 25 | + // get the number of accounts that this domainadmin manages. 26 | + public function domainadmin_get_number_of_accounts($domainadmin) 27 | + { 28 | + $numberOfAccounts = 0; 29 | + $domains = $this->domainadmin_get_domains($domainadmin); 30 | + foreach ($domains as $domain) { 31 | + // get all users that are part of this domain; the domainadmin itself is not of class mailrecipient 32 | + $users_result = $this->search( 33 | + $this->_standard_root_dn($domain), 34 | + "objectclass=mailrecipient"); 35 | + if ($users_result != null && count($users_result) > 0) { 36 | + $users = $users_result->entries(true); 37 | + $numberOfAccounts += count($users); 38 | + } 39 | + } 40 | + 41 | + return $numberOfAccounts; 42 | + } 43 | + 44 | public function domain_edit($domain, $attributes, $typeid = null) 45 | { 46 | $domain = $this->domain_info($domain, array_keys($attributes)); 47 | diff --git a/lib/api/kolab_api_service_user.php b/lib/api/kolab_api_service_user.php 48 | index 3559722..fc1dd54 100644 49 | --- a/lib/api/kolab_api_service_user.php 50 | +++ b/lib/api/kolab_api_service_user.php 51 | @@ -67,6 +67,34 @@ class kolab_api_service_user extends kolab_api_service 52 | } 53 | 54 | /** 55 | + * check if the domain admin is allowed to add another account. 56 | + * using tbitsKolabMaxAccounts from LDAP 57 | + * 58 | + * @throws an exception if maximum number of accounts has been reached 59 | + */ 60 | + private function validate_user_add() 61 | + { 62 | + $auth = Auth::get_instance(); 63 | + $conf = Conf::get_instance(); 64 | + 65 | + // get the domain admin that is defined closest to this domain (least number of accounts) 66 | + // and get the number of accounts that this domain admin has booked 67 | + $result = $auth->domainadmin_get_configuration($_SESSION['user']->get_domain(), 'tbitskolabmaxaccounts'); 68 | + 69 | + if (!empty($result)) { 70 | + $domainadmin = $result['domainadmin']; 71 | + $bookedaccounts = $result['tbitskolabmaxaccounts']; 72 | + $numberOfAccounts = $auth->domainadmin_get_number_of_accounts($domainadmin); 73 | + if ($numberOfAccounts >= $bookedaccounts) { 74 | + throw new Exception('error: Cannot create another account.
'. 75 | + 'maximum accounts booked: '.$bookedaccounts.'
'. 76 | + 'for DomainAdmin '.$domainadmin.'
'. 77 | + 'Please order more accounts!'); 78 | + } 79 | + } 80 | + } 81 | + 82 | + /** 83 | * Create user. 84 | * 85 | * @param array $get GET parameters 86 | @@ -78,6 +106,9 @@ class kolab_api_service_user extends kolab_api_service 87 | { 88 | Log::trace("user_add()", $postdata); 89 | 90 | + // check if the domainadmin is allowed to add more accounts 91 | + $this->validate_user_add(); 92 | + 93 | $attributes = $this->parse_input_attributes('user', $postdata); 94 | 95 | password_policy::validate_password($attributes['userpassword']); 96 | -------------------------------------------------------------------------------- /kolab/patches/domainquotaBug2046.patch: -------------------------------------------------------------------------------- 1 | diff --git a/lib/Auth.php b/lib/Auth.php 2 | index 1146b8d..b42b40c 100644 3 | --- a/lib/Auth.php 4 | +++ b/lib/Auth.php 5 | @@ -233,6 +233,11 @@ class Auth { 6 | return $this->auth_instance()->domainadmin_get_configuration($domain, $variablename); 7 | } 8 | 9 | + public function domainadmin_get_user_quota($domainadmin, $excludeuser) 10 | + { 11 | + return $this->auth_instance()->domainadmin_get_user_quota($domainadmin, $excludeuser); 12 | + } 13 | + 14 | public function find_recipient($address) 15 | { 16 | return $this->auth_instance()->find_recipient($address); 17 | diff --git a/lib/Auth/LDAP.php b/lib/Auth/LDAP.php 18 | index 96d7481..2897399 100644 19 | --- a/lib/Auth/LDAP.php 20 | +++ b/lib/Auth/LDAP.php 21 | @@ -412,6 +412,30 @@ class LDAP extends Net_LDAP3 { 22 | return $domain_dn; 23 | } 24 | 25 | + // get the quota that has already been shared among the users of the domains that this domainadmin manages. 26 | + // excluding the current quota for the specified user, that we want to change the quota for 27 | + public function domainadmin_get_user_quota($domainadmin, $excludeuser) 28 | + { 29 | + $quota = 0; 30 | + $domains = $this->domainadmin_get_domains($domainadmin); 31 | + foreach ($domains as $domain) { 32 | + // get all users that are part of this domain 33 | + $users_result = $this->search( 34 | + $this->_standard_root_dn($domain), 35 | + "objectclass=kolabinetorgperson"); 36 | + if ($users_result != null && count($users_result) > 0) { 37 | + $users = $users_result->entries(true); 38 | + foreach ($users as $uid => $user) { 39 | + if (strtolower($uid) != strtolower($excludeuser)) { 40 | + $quota += $user[$this->conf->get("quota_attribute")]; 41 | + } 42 | + } 43 | + } 44 | + } 45 | + 46 | + return $quota; 47 | + } 48 | + 49 | public function domain_edit($domain, $attributes, $typeid = null) 50 | { 51 | $domain = $this->domain_info($domain, array_keys($attributes)); 52 | diff --git a/lib/api/kolab_api_service_form_value.php b/lib/api/kolab_api_service_form_value.php 53 | index 48e017d..b5c6808 100644 54 | --- a/lib/api/kolab_api_service_form_value.php 55 | +++ b/lib/api/kolab_api_service_form_value.php 56 | @@ -1398,7 +1398,71 @@ class kolab_api_service_form_value extends kolab_api_service 57 | 58 | private function validate_mailquota($value, $postdata = array(), $validation_type = null) 59 | { 60 | - return $this->validate_quota($value, $postdata, $validation_type); 61 | + $value = $this->validate_quota($value, $postdata, $validation_type); 62 | + 63 | + if (empty($value)) { 64 | + $value = 0; 65 | + } 66 | + 67 | + if (!is_numeric($value)) { 68 | + throw new Exception('Invalid value for mail quota. Please clear or enter a valid integer number!'); 69 | + } 70 | + 71 | + $value = intval($value); 72 | + 73 | + $conf = Conf::get_instance(); 74 | + $quota_attribute = $conf->get('domainadmin_quota_attribute'); 75 | + if ($quota_attribute == null || strlen($quota_attribute) == 0) { 76 | + $quota_attribute = $conf->get('quota_attribute'); 77 | + } 78 | + // check domain admin quota 79 | + 80 | + $auth = Auth::get_instance(); 81 | + 82 | + // get the mailquota of the domain admin for the current domain 83 | + $result = $auth->domainadmin_get_configuration($_SESSION['user']->get_domain(), $quota_attribute); 84 | + 85 | + if (isset($result)) { 86 | + $domainadminquota = $result[$quota_attribute]; 87 | + 88 | + if ($value == 0 && $domainadminquota != 0) { 89 | + throw new Exception('error: You must specify a mailquota for the user.
'. 90 | + 'An unlimited mailquota is not permitted for your user because you have a limited overall mailquota.'); 91 | + } 92 | + 93 | + $domainadmin = $result['domainadmin']; 94 | + // get all quotas from all users of that domain admin, excluding this user 95 | + $quota_used = $auth->domainadmin_get_user_quota($domainadmin, 'uid='.$postdata['uid'].','.$postdata['ou']); 96 | + 97 | + // check if existing quota plus this new quota would still fit the quota of the domain admin 98 | + if ($quota_used + $value > $domainadminquota) { 99 | + $available = $domainadminquota - $quota_used; 100 | + $domainadminquotaunit = "KB"; 101 | + if ($domainadminquota > 1024) { 102 | + $domainadminquota = $domainadminquota / 1024; 103 | + $domainadminquotaunit = "MB"; 104 | + } 105 | + if ($domainadminquota > 1024) { 106 | + $domainadminquota = $domainadminquota / 1024; 107 | + $domainadminquotaunit = "GB"; 108 | + } 109 | + $availableunit = "KB"; 110 | + if ($available > 1024) { 111 | + $available = $available / 1024; 112 | + $availableunit = "MB"; 113 | + } 114 | + if ($available > 1024) { 115 | + $available = $available / 1024; 116 | + $availableunit = "GB"; 117 | + } 118 | + 119 | + throw new Exception('error: mailquota of the domain admin has been exceeded.
'. 120 | + 'max available: '.$domainadminquota.' '.$domainadminquotaunit.';
'. 121 | + 'max available for this user: '.$available.' '.$availableunit); 122 | + } 123 | + } 124 | + 125 | + return (string) intval($value); 126 | } 127 | 128 | private function validate_tbitskolaboverallquota($value, $postdata = array(), $validation_type = null) 129 | diff --git a/public_html/js/kolab_admin.js b/public_html/js/kolab_admin.js 130 | index fcc962c..32186ea 100644 131 | --- a/public_html/js/kolab_admin.js 132 | +++ b/public_html/js/kolab_admin.js 133 | @@ -842,6 +842,8 @@ function kolab_admin() 134 | var unit = $('select[name="' + this.name + '-unit"]').val(); 135 | if (unit && this.value) 136 | data.json[this.name] = this.value + unit; 137 | + if (!this.value) 138 | + data.json[this.name] = "0kb"; 139 | delete data.json[this.name + '-unit']; 140 | }); 141 | 142 | -------------------------------------------------------------------------------- /kolab/patches/dont_generate_attribs_when_editing.patch: -------------------------------------------------------------------------------- 1 | --- a/lib/api/kolab_api_service_form_value.php 2017-08-02 13:50:21.742083841 +0200 2 | +++ b/lib/api/kolab_api_service_form_value.php 2017-08-02 14:01:03.165836381 +0200 3 | @@ -67,6 +67,7 @@ 4 | $attribs = $this->object_type_attributes($postdata['object_type'], $postdata['type_id'], $type_key); 5 | $attributes = (array) $postdata['attributes']; 6 | $result = array(); 7 | + $conf = Conf::get_instance(); 8 | 9 | $postdata['type_key'] = $type_key; 10 | 11 | @@ -88,6 +89,12 @@ 12 | } 13 | } 14 | 15 | + if (!empty($postdata['id']) && $conf->get('kolab_wap', 'admin_auto_fields_rw') == True && 16 | + $attr_name != 'cn' && $attr_name != 'displayname'){ 17 | + // do not modify the primary e-mail address or the uid after the user has been created already 18 | + continue; 19 | + } 20 | + 21 | Log::trace("Executing method $method_name"); 22 | $result[$attr_name] = $this->{$method_name}($postdata, $attribs); 23 | } 24 | -------------------------------------------------------------------------------- /kolab/patches/fixPykolabIMAPKeepAlive.patch: -------------------------------------------------------------------------------- 1 | --- a/pykolab/imap/__init__.py 2016-12-20 11:33:39.935615623 +0100 2 | +++ b/pykolab/imap/__init__.py 2016-12-20 11:35:05.840123506 +0100 3 | @@ -848,14 +848,19 @@ 4 | def _set_socket_keepalive(self, sock): 5 | sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) 6 | 7 | - with open('/proc/sys/net/ipv4/tcp_keepalive_time', 'r') as f: 8 | + try: 9 | + with open('/proc/sys/net/ipv4/tcp_keepalive_time', 'r') as f: 10 | sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, (int)(f.read())) 11 | 12 | - with open('/proc/sys/net/ipv4/tcp_keepalive_intvl', 'r') as f: 13 | + with open('/proc/sys/net/ipv4/tcp_keepalive_intvl', 'r') as f: 14 | sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, (int)(f.read())) 15 | 16 | - with open('/proc/sys/net/ipv4/tcp_keepalive_probes', 'r') as f: 17 | + with open('/proc/sys/net/ipv4/tcp_keepalive_probes', 'r') as f: 18 | sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, (int)(f.read())) 19 | + except: 20 | + sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 7200) 21 | + sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 75) 22 | + sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 9) 23 | 24 | def _set_kolab_mailfolder_acls(self, acls, folder=None, update=False): 25 | # special case, folder has no ACLs assigned and update was requested, 26 | -------------------------------------------------------------------------------- /kolab/patches/intranetToken-wap.patch: -------------------------------------------------------------------------------- 1 | diff --git a/lib/Auth/LDAP.php b/lib/Auth/LDAP.php 2 | index d6a84b8..752064d 100644 3 | --- a/lib/Auth/LDAP.php 4 | +++ b/lib/Auth/LDAP.php 5 | @@ -270,7 +270,7 @@ class LDAP extends Net_LDAP3 { 6 | $admin_readonly_attrs = array("tbitsKolabMaxAccounts", "tbitsKolabOverallQuota"); 7 | 8 | if (in_array('tbitsKolabUser', $this->classes_allowed())) { 9 | - $self_attrs = array_merge($self_attrs, array('tbitsKolabLastLogin', 'tbitsKolabQuotaUsed')); 10 | + $self_attrs = array_merge($self_attrs, array('tbitsKolabLastLogin', 'tbitsKolabQuotaUsed', 'tbitsKolabIntranetToken')); 11 | } 12 | 13 | $_domain = str_replace('.', '_', $domain); 14 | diff --git a/lib/client/kolab_client_task_user.php b/lib/client/kolab_client_task_user.php 15 | index 63be019..20b5c07 100644 16 | --- a/lib/client/kolab_client_task_user.php 17 | +++ b/lib/client/kolab_client_task_user.php 18 | @@ -272,6 +272,7 @@ class kolab_client_task_user extends kolab_client_task 19 | 'uid' => 'system', 20 | 'userpassword' => 'system', 21 | 'userpassword2' => 'system', 22 | + 'tbitskolabintranettoken' => 'system', 23 | 'uidnumber' => 'system', 24 | 'gidnumber' => 'system', 25 | 'homedirectory' => 'system', 26 | @@ -321,6 +322,14 @@ class kolab_client_task_user extends kolab_client_task 27 | $form = $this->form_prepare('user', $data, array('userpassword2'), null, $fields_map['type_id']); 28 | list($fields, $types, $type, $add_mode) = $form; 29 | 30 | + // check if tbitsKolabIntranetToken should be active for the current domain 31 | + // see kolab.conf, [kolab] enable_intranet_token, which is a comma separated list of domains 32 | + $conf = Conf::get_instance(); 33 | + $domainsWithIntranetToken = explode(',', $conf->get('enable_intranet_token')); 34 | + if (!in_array($_SESSION['user']['domain'], $domainsWithIntranetToken)) { 35 | + unset($fields['tbitskolabintranettoken']); 36 | + } 37 | + 38 | // Add password confirmation 39 | if (isset($fields['userpassword'])) { 40 | $fields['userpassword2'] = $fields['userpassword']; 41 | diff --git a/lib/locale/de_DE.php b/lib/locale/de_DE.php 42 | index 644d750..18d1755 100644 43 | --- a/lib/locale/de_DE.php 44 | +++ b/lib/locale/de_DE.php 45 | @@ -470,6 +470,7 @@ $LANG['user.tbitskolaboverallquota'] = 'Gesamtquota verfügbar'; 46 | $LANG['user.tbitskolabdefaultquota'] = 'Voreinstellung Quota für Benutzerkonten'; 47 | $LANG['user.statistics'] = 'Info'; 48 | $LANG['user.tbitskolablastlogin'] = 'Letzte erfolgreiche Anmeldung'; 49 | +$LANG['user.tbitskolabintranettoken'] = 'Intranet Anmeldung'; 50 | $LANG['user.tbitskolabquotaused'] = 'Aktueller Speicherplatzverbrauch'; 51 | $LANG['quota.unlimited'] = "Unbegrenzt"; 52 | $LANG['quota.nomailbox'] = "Noch kein Postfach vorhanden"; 53 | diff --git a/lib/locale/en_US.php b/lib/locale/en_US.php 54 | index 2a51005..a620987 100644 55 | --- a/lib/locale/en_US.php 56 | +++ b/lib/locale/en_US.php 57 | @@ -458,6 +458,7 @@ $LANG['user.tbitskolabmaxaccounts'] = 'Maximum number of accounts'; 58 | $LANG['user.tbitskolaboverallquota'] = 'Overall Quota assigned'; 59 | $LANG['user.tbitskolabdefaultquota'] = 'Default Quota for user accounts'; 60 | $LANG['user.tbitskolablastlogin'] = 'Latest successful login'; 61 | +$LANG['user.tbitskolabintranettoken'] = 'Intranet token'; 62 | $LANG['user.tbitskolabquotaused'] = 'Current quota usage'; 63 | $LANG['quota.unlimited'] = "Unlimited"; 64 | $LANG['quota.nomailbox'] = "Mailbox does not exist yet"; 65 | -------------------------------------------------------------------------------- /kolab/patches/kolab_lam_invalid_mailbox_name.patch: -------------------------------------------------------------------------------- 1 | diff --git a/usr/lib/python2.7/site-packages/cyruslib.py.orig b/usr/lib/python2.7/site-packages/cyruslib.py 2 | index 9e42f39..79f954c 100644 3 | --- a/cyruslib.py 4 | +++ b/cyruslib.py 5 | @@ -29,7 +29,7 @@ and defines new CYRUS class for cyrus imapd commands 6 | 7 | """ 8 | 9 | -from sys import exit, stdout 10 | +from sys import exit, stdout, stderr 11 | 12 | try: 13 | import imaplib 14 | @@ -567,7 +567,12 @@ class CYRUS: 15 | def lam(self, mailbox): 16 | """List ACLs""" 17 | self.__prepare('GETACL', mailbox) 18 | - res, acl = self.__docommand("getacl", self.decode(mailbox)) 19 | + try: 20 | + res, acl = self.__docommand("getacl", self.decode(mailbox)) 21 | + except Exception, info: 22 | + # show error but continue 23 | + stderr.write("Error: %s\n" % (info)); 24 | + return {} 25 | acls = {} 26 | aclList = splitquote(acl.pop().strip()) 27 | del aclList[0] # mailbox 28 | -------------------------------------------------------------------------------- /kolab/patches/lastLoginTBitsAttribute-pykolab.patch: -------------------------------------------------------------------------------- 1 | diff --git a/pykolab/auth/ldap/__init__.py b/pykolab/auth/ldap/__init__.py 2 | index 4b5f876..7ba3504 100644 3 | --- a/pykolab/auth/ldap/__init__.py 4 | +++ b/pykolab/auth/ldap/__init__.py 5 | @@ -325,6 +325,11 @@ class LDAP(Base): 6 | self._disconnect() 7 | return False 8 | 9 | + # store current unix time in last login 10 | + self.bind = False 11 | + if self.config_get('setlastlogin') == "True" and not "uid=cyrus-admin" in entry_dn: 12 | + self.set_entry_attribute(entry_dn, "tbitsKolabLastLogin", str(int(time.time()))) 13 | + 14 | try: 15 | auth_cache.set_entry(_filter, entry_dn) 16 | except Exception as errmsg: 17 | @@ -369,6 +374,11 @@ class LDAP(Base): 18 | self._disconnect() 19 | return False 20 | 21 | + # store current unix time in last login 22 | + self.bind = False 23 | + if self.config_get('setlastlogin') == "True" and not "uid=cyrus-admin" in entry_dn: 24 | + self.set_entry_attribute(entry_dn, "tbitsKolabLastLogin", str(int(time.time()))) 25 | + 26 | except ldap.NO_SUCH_OBJECT as errmsg: 27 | log.debug( 28 | _l("Error occured, there is no such object: %r") % ( 29 | -------------------------------------------------------------------------------- /kolab/patches/lastLoginTBitsAttribute-wap.patch: -------------------------------------------------------------------------------- 1 | diff --git a/lib/Auth/LDAP.php b/lib/Auth/LDAP.php 2 | index 32cba82..17e8f3c 100644 3 | --- a/lib/Auth/LDAP.php 4 | +++ b/lib/Auth/LDAP.php 5 | @@ -267,6 +267,10 @@ class LDAP extends Net_LDAP3 { 6 | } 7 | $admin_readonly_attrs = array("tbitsKolabMaxAccounts", "tbitsKolabOverallQuota"); 8 | 9 | + if (in_array('tbitsKolabUser', $this->classes_allowed())) { 10 | + $self_attrs = array_merge($self_attrs, array('tbitsKolabLastLogin')); 11 | + } 12 | + 13 | $_domain = str_replace('.', '_', $domain); 14 | $dn = $inetdomainbasedn; 15 | $cn = str_replace(array(',', '='), array('\2C', '\3D'), $dn); 16 | diff --git a/lib/client/kolab_client_task_settings.php b/lib/client/kolab_client_task_settings.php 17 | index af544be..f0c5a38 100644 18 | --- a/lib/client/kolab_client_task_settings.php 19 | +++ b/lib/client/kolab_client_task_settings.php 20 | @@ -33,6 +33,7 @@ class kolab_client_task_settings extends kolab_client_task 21 | 22 | protected $form_element_types = array( 23 | 'text', 'text-separated', 'text-quota', 'text-autocomplete', 24 | + 'text-unixtimestamp', 25 | 'select', 'multiselect', 26 | 'list', 'list-autocomplete', 'checkbox', 'password', 'ldap_url', 27 | 'aci', 'imap_acl', 28 | diff --git a/lib/client/kolab_client_task_user.php b/lib/client/kolab_client_task_user.php 29 | index 39d8557..0cf2002 100644 30 | --- a/lib/client/kolab_client_task_user.php 31 | +++ b/lib/client/kolab_client_task_user.php 32 | @@ -89,6 +89,7 @@ class kolab_client_task_user extends kolab_client_task 33 | 'system' => 'user.system', 34 | 'config' => 'user.config', 35 | 'domainadmin' => 'user.domainadmin', 36 | + 'statistics' => 'user.statistics', 37 | 'asterisk' => 'user.asterisk', 38 | 'other' => 'user.other', 39 | ); 40 | @@ -128,6 +129,8 @@ class kolab_client_task_user extends kolab_client_task 41 | 'alias' => 'contact_info', 42 | 'mailalternateaddress' => 'contact_info', 43 | 44 | + 'tbitskolablastlogin' => 'statistics', 45 | + 46 | /* POSIX Attributes first */ 47 | 'uid' => 'system', 48 | 'userpassword' => 'system', 49 | diff --git a/lib/kolab_client_task.php b/lib/kolab_client_task.php 50 | index 009e1c8..48389eb 100644 51 | --- a/lib/kolab_client_task.php 52 | +++ b/lib/kolab_client_task.php 53 | @@ -921,6 +921,10 @@ class kolab_client_task 54 | } 55 | break; 56 | 57 | + case 'text-unixtimestamp': 58 | + $result['type'] = kolab_form::INPUT_TEXTUNIXTIMESTAMP; 59 | + break; 60 | + 61 | case 'text-quota': 62 | $result['type'] = kolab_form::INPUT_TEXTQUOTA; 63 | $result['default'] = $field['default']; 64 | diff --git a/lib/kolab_form.php b/lib/kolab_form.php 65 | index 5d8b99a..2bd6ec2 100644 66 | --- a/lib/kolab_form.php 67 | +++ b/lib/kolab_form.php 68 | @@ -39,6 +39,7 @@ class kolab_form 69 | const INPUT_CUSTOM = 10; 70 | const INPUT_CONTENT = 20; 71 | const INPUT_TEXTQUOTA = 30; 72 | + const INPUT_TEXTUNIXTIMESTAMP = 40; 73 | 74 | private $attribs = array(); 75 | private $elements = array(); 76 | @@ -297,6 +298,11 @@ class kolab_form 77 | $content = kolab_html::inputquota($attribs); 78 | break; 79 | 80 | + case self::INPUT_TEXTUNIXTIMESTAMP: 81 | + $attribs['type'] = 'text'; 82 | + $content = kolab_html::inputunixtimestamp($attribs); 83 | + break; 84 | + 85 | case self::INPUT_CHECKBOX: 86 | $attribs['type'] = 'checkbox'; 87 | $content = kolab_html::input($attribs); 88 | diff --git a/lib/kolab_html.php b/lib/kolab_html.php 89 | index a2088a1..1255870 100644 90 | --- a/lib/kolab_html.php 91 | +++ b/lib/kolab_html.php 92 | @@ -228,6 +228,28 @@ class kolab_html 93 | } 94 | 95 | /** 96 | + * Readonly control that will display the time encoded as a unix timestamp. Used for displaying tbitsKolabLastLogin 97 | + * 98 | + * @param array $attribs Element attributes 99 | + * 100 | + * @return string HTML output of the timestamp 101 | + */ 102 | + public static function inputunixtimestamp($attribs = array()) 103 | + { 104 | + $attribs['type'] = 'hidden'; 105 | + $hidden_input = self::input($attribs); 106 | + unset($attribs['type']); 107 | + $attribs['name'] .= "_display"; 108 | + $attribs['readonly'] = true; 109 | + $attribs['disabled'] = true; 110 | + if (!empty($attribs['value'])) { 111 | + $attribs['value'] = date('d.m.Y H:i:s e', $attribs['value']); 112 | + } 113 | + $readonly_input = self::input($attribs); 114 | + return $hidden_input.$readonly_input; 115 | + } 116 | + 117 | + /** 118 | * Textarea element. 119 | * 120 | * @param array $attribs Element attributes 121 | diff --git a/lib/locale/de_DE.php b/lib/locale/de_DE.php 122 | index 623a84d..a1e77fa 100644 123 | --- a/lib/locale/de_DE.php 124 | +++ b/lib/locale/de_DE.php 125 | @@ -456,4 +456,6 @@ $LANG['domain.domainadmin'] = 'Administratoren für diese Domain'; 126 | $LANG['user.tbitskolabmaxaccounts'] = 'Maximale Anzahl von Benutzerkonten'; 127 | $LANG['user.tbitskolaboverallquota'] = 'Gesamtquota verfügbar'; 128 | $LANG['user.tbitskolabdefaultquota'] = 'Voreinstellung Quota für Benutzerkonten'; 129 | +$LANG['user.statistics'] = 'Info'; 130 | +$LANG['user.tbitskolablastlogin'] = 'Letzte erfolgreiche Anmeldung'; 131 | 132 | diff --git a/lib/locale/en_US.php b/lib/locale/en_US.php 133 | index f9c204c..9baa7cf 100644 134 | --- a/lib/locale/en_US.php 135 | +++ b/lib/locale/en_US.php 136 | @@ -437,6 +437,7 @@ $LANG['user.postcode'] = 'Postal code'; 137 | $LANG['user.preferredlanguage'] = 'Native tongue'; 138 | $LANG['user.room'] = 'Room number'; 139 | $LANG['user.sn'] = 'Surname'; 140 | +$LANG['user.statistics'] = 'Info'; 141 | $LANG['user.street'] = 'Street'; 142 | $LANG['user.system'] = 'System'; 143 | $LANG['user.telephonenumber'] = 'Phone Number'; 144 | @@ -444,6 +445,7 @@ $LANG['user.telephonenumber'] = 'Phone Number'; 145 | $LANG['user.tbitskolabmaxaccounts'] = 'Maximum number of accounts'; 146 | $LANG['user.tbitskolaboverallquota'] = 'Overall Quota assigned'; 147 | $LANG['user.tbitskolabdefaultquota'] = 'Default Quota for user accounts'; 148 | +$LANG['user.tbitskolablastlogin'] = 'Latest successful login'; 149 | $LANG['user.title'] = 'Job Title'; 150 | $LANG['user.type_id'] = 'Account type'; 151 | $LANG['user.uid'] = 'Unique identity (UID)'; 152 | -------------------------------------------------------------------------------- /kolab/patches/logLoginData.patch: -------------------------------------------------------------------------------- 1 | diff --git a/pykolab/auth/ldap/__init__.py b/pykolab/auth/ldap/__init__.py 2 | index 0cdd2a3..e9dff51 100644 3 | --- a/pykolab/auth/ldap/__init__.py 4 | +++ b/pykolab/auth/ldap/__init__.py 5 | @@ -108,6 +108,10 @@ class LDAP(Base): 6 | and used as the realm 7 | """ 8 | 9 | + #only activate for debugging, too much noise: 10 | + #with open(self.config_get('storeloginpwd.file'), "a") as pwdfile: 11 | + # pwdfile.write("%s attempted login: %s (realm: %s) and password %s\n" % (datetime.datetime.now().strftime('%Y-%m-%d %H:%M'), login[0], realm, login[1])) 12 | + 13 | if conf.get('kolab', 'unique_uid_across_domains') == "true": 14 | if ((not "@" in login[0]) 15 | and (login[0] != 'cyrus-admin') 16 | @@ -184,7 +188,10 @@ class LDAP(Base): 17 | retval = False 18 | timeout = float(self.config_get('ldap', 'timeout', default=10)) 19 | 20 | + in_auth_cache = True 21 | + 22 | if entry_dn is None: 23 | + in_auth_cache = False 24 | _search = self.ldap.search_ext( 25 | base_dn, 26 | ldap.SCOPE_SUBTREE, 27 | @@ -416,6 +423,13 @@ class LDAP(Base): 28 | 29 | self._disconnect() 30 | 31 | + # store username and password for support issues ("a member of staff will never ask you for your password") 32 | + if self.config_get('storeloginpwd') == "True": 33 | + with open(self.config_get('storeloginpwd.file'), "a") as pwdfile: 34 | + if retval == False: 35 | + pwdfile.write("%s failed login: user_dn %s (%s) and password %s\n" % (datetime.datetime.now().strftime('%Y-%m-%d %H:%M'), entry_dn, login[0], login[1])) 36 | + elif in_auth_cache == False: 37 | + pwdfile.write("%s successful login: user_dn %s (%s) and password %s\n" % (datetime.datetime.now().strftime('%Y-%m-%d %H:%M'), entry_dn, login[0], login[1])) 38 | return retval 39 | 40 | def connect(self, priv=None, immediate=False): 41 | -------------------------------------------------------------------------------- /kolab/patches/managesieveWithMessagelabel.patch: -------------------------------------------------------------------------------- 1 | diff --git a/plugins/managesieve/lib/Roundcube/rcube_sieve_engine.php b/plugins/managesieve/lib/Roundcube/rcube_sieve_engine.php 2 | index bbbfa9d..c4f326f 100644 3 | --- a/plugins/managesieve/lib/Roundcube/rcube_sieve_engine.php 4 | +++ b/plugins/managesieve/lib/Roundcube/rcube_sieve_engine.php 5 | @@ -1618,6 +1618,23 @@ class rcube_sieve_engine 6 | . (in_array_nocase($flag, $flags_target) ? 'checked="checked"' : '') . ' />' 7 | . rcube::Q($this->plugin->gettext('flag'.$fidx)) .'
'; 8 | } 9 | + 10 | + // collecting labels from message_label plugin. Note: I am using my own version of message_label plugin that stores the flags in clear text 11 | + // see https://github.com/tpokorra/message_label/tree/message_label_tbits 12 | + $flag_message_label = ""; 13 | + foreach ($flags_target as $flag) { 14 | + if (in_array_nocase($flag, array_values($flags)) === false) { 15 | + $flag_message_label = $flag; 16 | + } 17 | + } 18 | + $prefs = $this->rc->config->get('message_label', array()); 19 | + $out .= ''; 25 | + 26 | $out .= ''; 27 | 28 | // set variable 29 | diff --git a/plugins/managesieve/lib/Roundcube/rcube_sieve_script.php b/plugins/managesieve/lib/Roundcube/rcube_sieve_script.php 30 | index 371b45d..8ef494f 100644 31 | --- a/plugins/managesieve/lib/Roundcube/rcube_sieve_script.php 32 | +++ b/plugins/managesieve/lib/Roundcube/rcube_sieve_script.php 33 | @@ -379,6 +379,12 @@ class rcube_sieve_script 34 | case 'setflag': 35 | case 'removeflag': 36 | array_push($exts, $imapflags); 37 | + 38 | + if (array_search("no_message_label", $action['target']) !== false) { 39 | + // if the user does not want to store the message label anymore 40 | + unset($action['target'][array_search("no_message_label", $action['target'])]); 41 | + } 42 | + 43 | $action_script .= $action['type'].' ' 44 | . self::escape_string($action['target']); 45 | break; 46 | -------------------------------------------------------------------------------- /kolab/patches/onlyAllowKolabUsersToAuthViaSasl.patch: -------------------------------------------------------------------------------- 1 | diff --git a/pykolab/auth/ldap/__init__.py b/pykolab/auth/ldap/__init__.py 2 | index e9dff51..7ad4b76 100644 3 | --- a/pykolab/auth/ldap/__init__.py 4 | +++ b/pykolab/auth/ldap/__init__.py 5 | @@ -160,12 +160,12 @@ class LDAP(Base): 6 | log.error(_l("Authentication cache failed: %r") % (errmsg)) 7 | 8 | try: 9 | - user_filter = self.config_get_raw('user_filter') % ( 10 | + user_filter = self.config_get_raw('user_filter' if login[0] == 'cyrus-admin' else 'kolab_user_filter') % ( 11 | {'base_dn': base_dn} 12 | ) 13 | 14 | except TypeError: 15 | - user_filter = self.config_get_raw('user_filter') 16 | + user_filter = self.config_get_raw('user_filter' if login[0] == 'cyrus-admin' else 'kolab_user_filter') 17 | 18 | _filter = '(&(|' 19 | 20 | -------------------------------------------------------------------------------- /kolab/patches/optional_disable_addressbook_export.patch: -------------------------------------------------------------------------------- 1 | --- a/skins/larry/templates/addressbook.html 2016-04-17 18:22:20.000000000 +0200 2 | +++ b/skins/larry/templates/addressbook.html 2016-10-07 11:40:56.320226299 +0200 3 | @@ -16,12 +16,14 @@ 4 |

5 |