ofreax 9 years ago
parent
commit
53c90df3da

+ 53 - 40
CHANGELOG.md

@@ -1,79 +1,92 @@
 # Changelog
 # Changelog
 
 
 ## 1.1.0
 ## 1.1.0
-  - Update to light-baseimage:0.2.1
-  - Use cfssl to generate ssl certs
+Update to light-baseimage:0.2.1 :
+  - Use *.yaml.setup environment files to keep configuration secrets
+  - Use cfssl tool to generate tls certs
+  - Use log-helper to write leveled log messages
+  - Allow copy of /container/service and mounted files to /container/run/service dir usefull for write only filesystems and avoid file permissions problems
+
+New feature :
+  - Add enforcing TLS options (#26)
+
+Fix :
+  - Should SSL certs be copied on load? (#25)
 
 
 ## 1.0.9
 ## 1.0.9
-  - Update to light-baseimage:0.2.0
-  - Makefile with build no cache
+Update to light-baseimage:0.2.0
+
+Makefile with build no cache
 
 
 ## 1.0.8
 ## 1.0.8
-  - Fix an other startup bug ! whuhu
+Fix an other startup bug ! whuhu
 
 
 ## 1.0.7
 ## 1.0.7
-  - Fix startup bug
+Fix startup bug
 
 
 ## 1.0.6
 ## 1.0.6
-  - Use light-baseimage:0.1.5
+Use light-baseimage:0.1.5
 
 
 ## 1.0.5
 ## 1.0.5
-  - Use light-baseimage:0.1.4
-  - Fix replication bug when the hostname was changed
+Use light-baseimage:0.1.4
+
+Fix replication bug when the hostname was changed
 
 
 ## 1.0.4
 ## 1.0.4
-  - Use light-baseimage:0.1.3
+Use light-baseimage:0.1.3
 
 
 ## 1.0.3
 ## 1.0.3
-  - Use light-baseimage:0.1.2
-  - Fixes :
-    - Re-running container with volumes won't start #19
+Use light-baseimage:0.1.2
+
+Fix :
+  - Re-running container with volumes won't start #19
 
 
 ## 1.0.2
 ## 1.0.2
 
 
-  - Add TLS environment variable :
-      - LDAP_TLS_CIPHER_SUITE
-      - LDAP_TLS_PROTOCOL_MIN
-      - LDAP_TLS_VERIFY_CLIENT
+Add TLS environment variable :
+  - LDAP_TLS_CIPHER_SUITE
+  - LDAP_TLS_PROTOCOL_MIN
+  - LDAP_TLS_VERIFY_CLIENT
 
 
 ## 1.0.1
 ## 1.0.1
 
 
-  - Upgrade baseimage: light-baseimage:0.1.1
-  - Rename environment variables
+Upgrade baseimage: light-baseimage:0.1.1
+
+Rename environment variables
 
 
-  - Fixes :
-    - OpenLdap container won't start when dhparam.pem is missing in bound volume #13
+Fix :
+  - OpenLdap container won't start when dhparam.pem is missing in bound volume #13
 
 
 ## 1.0.0
 ## 1.0.0
 
 
-  - Use light-baseimage
-  - Improve documentation
+Use light-baseimage
+
+Improve documentation
 
 
 ## 0.10.2
 ## 0.10.2
 
 
-  - New features:
-    - Bootstrap config, only on non existing slapd config
-    - Limit max open file descriptors to fix slapd memory usage (#9)
-    - Don't disable network access from outside (#8)
-    - Make log level configurable via environment variable (#7)
-    - Support for ldaps (#10)
+New features :
+  - Bootstrap config, only on non existing slapd config
+  - Limit max open file descriptors to fix slapd memory usage (#9)
+  - Don't disable network access from outside (#8)
+  - Make log level configurable via environment variable (#7)
+  - Support for ldaps (#10)
 
 
 
 
-  - Fixes:
-    - Unable to start container with the following invocation. (#6)
+Fix :
+  - Unable to start container with the following invocation. (#6)
 
 
 ## 0.10.1
 ## 0.10.1
 
 
-  - New features:
-    - Add ldapi
-    - Add ldapi
-    - Add custom ldap schema
-    - Auto convert .schema to .ldif
+New features :
+  - Add ldapi
+  - Add custom ldap schema
+  - Auto convert .schema to .ldif
 
 
 
 
-  - Fixes :
-    - Docker VOLUME is not needed to be able to stop a container without losing data (#2)
-    - starting from old data (#3)
+Fix :
+  - Docker VOLUME is not needed to be able to stop a container without losing data (#2)
+  - starting from old data (#3)
 
 
 ## 0.10.0
 ## 0.10.0
-  - New version initial release
+New version initial release

+ 103 - 45
README.md

@@ -11,17 +11,11 @@ Support TLS, multi-master replication and quick bootstrap.
 ## Quick Start
 ## Quick Start
 Run OpenLDAP docker image :
 Run OpenLDAP docker image :
 
 
-	docker run --name my-openldap-container -d osixia/openldap:1.1.0
+	docker run --name my-openldap-container --detach osixia/openldap:1.1.0
 
 
-This start a new container with OpenLDAP running inside. Let's make our first search in our LDAP server.
+This start a new container with OpenLDAP running inside. Let's make the first search in our LDAP container:
 
 
-Open a bash in the container :
-
-	docker exec -it my-openldap-container bash
-
-In the container terminal run the following commands :
-
-	ldapsearch -x -h localhost -b dc=example,dc=org -D "cn=admin,dc=example,dc=org" -w admin
+	docker exec my-openldap-container ldapsearch -x -h localhost -b dc=example,dc=org -D "cn=admin,dc=example,dc=org" -w admin
 
 
 This should output :
 This should output :
 
 
@@ -38,7 +32,7 @@ This should output :
 	# numResponses: 3
 	# numResponses: 3
 	# numEntries: 2
 	# numEntries: 2
 
 
-if you have the following error, OpenLDAP is not started yet, you are too fast or your computer is too slow (it's a matter of  point of view) wait some time.
+if you have the following error, OpenLDAP is not started yet, you are too fast ;) ... wait some time.
 
 
 		ldap_sasl_bind(SIMPLE): Can't contact LDAP server (-1)
 		ldap_sasl_bind(SIMPLE): Can't contact LDAP server (-1)
 
 
@@ -53,7 +47,7 @@ It will create an empty ldap for the compagny **Example Inc.** and the domain **
 By default the admin has the password **admin**. All those default settings can be changed at the docker command line, for example :
 By default the admin has the password **admin**. All those default settings can be changed at the docker command line, for example :
 
 
 	docker run --env LDAP_ORGANISATION="My Compagny" --env LDAP_DOMAIN="my-compagny.com" \
 	docker run --env LDAP_ORGANISATION="My Compagny" --env LDAP_DOMAIN="my-compagny.com" \
-	--env LDAP_ADMIN_PASSWORD="JonSn0w" -d osixia/openldap
+	--env LDAP_ADMIN_PASSWORD="JonSn0w" --detach osixia/openldap:1.1.0
 
 
 #### Data persitance
 #### Data persitance
 
 
@@ -71,9 +65,9 @@ Assuming you have a LDAP database on your docker host in the directory `/data/sl
 and the corresponding LDAP config files on your docker host in the directory `/data/slapd/config`
 and the corresponding LDAP config files on your docker host in the directory `/data/slapd/config`
 simply mount this directories as a volume to `/var/lib/ldap` and `/etc/ldap/slapd.d`:
 simply mount this directories as a volume to `/var/lib/ldap` and `/etc/ldap/slapd.d`:
 
 
-	docker run -v /data/slapd/database:/var/lib/ldap \
-	-v /data/slapd/config:/etc/ldap/slapd.d
-	-d osixia/openldap
+	docker run --volume /data/slapd/database:/var/lib/ldap \
+	--volume /data/slapd/config:/etc/ldap/slapd.d
+	--detach osixia/openldap:1.1.0
 
 
 You can also use data volume containers. Please refer to :
 You can also use data volume containers. Please refer to :
 > [https://docs.docker.com/userguide/dockervolumes/](https://docs.docker.com/userguide/dockervolumes/)
 > [https://docs.docker.com/userguide/dockervolumes/](https://docs.docker.com/userguide/dockervolumes/)
@@ -81,36 +75,36 @@ You can also use data volume containers. Please refer to :
 ### TLS
 ### TLS
 
 
 #### Use autogenerated certificate
 #### Use autogenerated certificate
-By default TLS is enable, a certificate is created with the container hostname (it can be set by docker run -h option eg: ldap.example.org).
+By default TLS is enable, a certificate is created with the container hostname (it can be set by docker run --hostname option eg: ldap.example.org).
 
 
-	docker run -h ldap.my-compagny.com -d osixia/openldap
+	docker run --hostname ldap.my-compagny.com --detach osixia/openldap:1.1.0
 
 
 #### Use your own certificate
 #### Use your own certificate
 
 
-Add your custom certificate, private key and CA certificate in the directory **image/service/slapd/assets/certs** adjust filename in **image/env.yaml** and rebuild the image ([see manual build](#manual-build)).
+You can set your custom certificate at run time, by mouting a directory containing thoses files to **/container/service/slapd/assets/certs** and adjust there name with the following environment variables :
 
 
-Or you can set your custom certificate at run time, by mouting a directory containing thoses files to **/container/service/slapd/assets/certs** and adjust there name with the following environment variables :
-
-	docker run -h ldap.example.org -v /path/to/certifates:/container/service/slapd/assets/certs \
+	docker run --hostname ldap.example.org --volume /path/to/certifates:/container/service/slapd/assets/certs \
 	--env LDAP_TLS_CRT_FILENAME=my-ldap.crt \
 	--env LDAP_TLS_CRT_FILENAME=my-ldap.crt \
 	--env LDAP_TLS_KEY_FILENAME=my-ldap.key \
 	--env LDAP_TLS_KEY_FILENAME=my-ldap.key \
 	--env LDAP_TLS_CA_CRT_FILENAME=the-ca.crt \
 	--env LDAP_TLS_CA_CRT_FILENAME=the-ca.crt \
-	-d osixia/openldap
+	--detach osixia/openldap:1.1.0
+
+Other solutions are available please refer to the [Advanced User Guide](#advanced-user-guide)
 
 
 #### Disable TLS
 #### Disable TLS
 Add --env LDAP_TLS=false to the run command :
 Add --env LDAP_TLS=false to the run command :
 
 
-	docker run --env LDAP_TLS=false -d osixia/openldap
+	docker run --env LDAP_TLS=false --detach osixia/openldap:1.1.0
 
 
 ### Multi master replication
 ### Multi master replication
 Quick example, with the default config.
 Quick example, with the default config.
 
 
 	#Create the first ldap server, save the container id in LDAP_CID and get its IP:
 	#Create the first ldap server, save the container id in LDAP_CID and get its IP:
-	LDAP_CID=$(docker run -h ldap.example.org --env LDAP_REPLICATION=true -d osixia/openldap)
+	LDAP_CID=$(docker run --hostname ldap.example.org --env LDAP_REPLICATION=true --detach osixia/openldap:1.1.0)
 	LDAP_IP=$(docker inspect -f "{{ .NetworkSettings.IPAddress }}" $LDAP_CID)
 	LDAP_IP=$(docker inspect -f "{{ .NetworkSettings.IPAddress }}" $LDAP_CID)
 
 
 	#Create the second ldap server, save the container id in LDAP2_CID and get its IP:
 	#Create the second ldap server, save the container id in LDAP2_CID and get its IP:
-	LDAP2_CID=$(docker run -h ldap2.example.org --env LDAP_REPLICATION=true -d osixia/openldap)
+	LDAP2_CID=$(docker run --hostname ldap2.example.org --env LDAP_REPLICATION=true --detach osixia/openldap:1.1.0)
 	LDAP2_IP=$(docker inspect -f "{{ .NetworkSettings.IPAddress }}" $LDAP2_CID)
 	LDAP2_IP=$(docker inspect -f "{{ .NetworkSettings.IPAddress }}" $LDAP2_CID)
 
 
 	#Add the pair "ip hostname" to /etc/hosts on each containers,
 	#Add the pair "ip hostname" to /etc/hosts on each containers,
@@ -122,7 +116,7 @@ That's it ! But a litle test to be sure :
 
 
 Add a new user "billy" on the first ldap server
 Add a new user "billy" on the first ldap server
 
 
-	docker exec $LDAP_CID ldapadd -x -D "cn=admin,dc=example,dc=org" -w admin -f /container/service/slapd/assets/test/new-user.ldif -h ldap.example.org -ZZ
+	docker exec $LDAP_CID ldapadd -x -D "cn=admin,dc=example,dc=org" -w admin -f /container/service/slapd/assets/test/new-user.ldif --hostname ldap.example.org -ZZ
 
 
 Search on the second ldap server, and billy should show up !
 Search on the second ldap server, and billy should show up !
 
 
@@ -149,9 +143,7 @@ A simple solution to backup your ldap server, our openldap-backup docker image :
 > [osixia/openldap-backup](https://github.com/osixia/docker-openldap-backup)
 > [osixia/openldap-backup](https://github.com/osixia/docker-openldap-backup)
 
 
 ## Default Environment Variables
 ## Default Environment Variables
-Environement variables defaults are set in **image/environment/default.yaml** and **image/environment/default.yaml.startup**.
-
-Go to next point to see how to set your own environment variables.
+Environement variables defaults are set in **image/environment/default.yaml** and **image/environment/default.yaml.setup**.
 
 
 ### default.yaml
 ### default.yaml
 Variables defined in this file are available at any time, anywhere in the container environment.
 Variables defined in this file are available at any time, anywhere in the container environment.
@@ -159,11 +151,12 @@ Variables defined in this file are available at any time, anywhere in the contai
 General container configuration :
 General container configuration :
 - **LDAP_LOG_LEVEL**: Slap log level. defaults to  `256`. See table 5.1 in http://www.openldap.org/doc/admin24/slapdconf2.html for the available log levels.
 - **LDAP_LOG_LEVEL**: Slap log level. defaults to  `256`. See table 5.1 in http://www.openldap.org/doc/admin24/slapdconf2.html for the available log levels.
 
 
-### default.yaml.startup
+### default.yaml.setup
 Variables defined in this file are only available during the container **first start** in **startup scripts**.
 Variables defined in this file are only available during the container **first start** in **startup scripts**.
 This file is deleted right after startup scripts are processed for the first time,
 This file is deleted right after startup scripts are processed for the first time,
-after that all theses values will not be available in the container environment.
-That helps to keep your container configuration secret.
+after that all these values will not be available in the container environment.
+
+That helps to keep your container configuration secret. If you don't care all environment variables can be defined in **default.yaml** and everything will work fine :)
 
 
 Required and used for new ldap server only :
 Required and used for new ldap server only :
 - **LDAP_ORGANISATION**: Organisation name. Defaults to `Example Inc.`
 - **LDAP_ORGANISATION**: Organisation name. Defaults to `Example Inc.`
@@ -193,44 +186,66 @@ Replication options :
 
 
 - **LDAP_REPLICATION_HDB_SYNCPROV**: olcSyncRepl options used for the HDB database. Without **rid** and **provider** which are automaticaly added based on LDAP_REPLICATION_HOSTS.  Defaults to `binddn="cn=admin,$LDAP_BASE_DN" bindmethod=simple credentials=$LDAP_ADMIN_PASSWORD searchbase="$LDAP_BASE_DN" type=refreshAndPersist interval=00:00:00:10 retry="60 +" timeout=1 starttls=critical`
 - **LDAP_REPLICATION_HDB_SYNCPROV**: olcSyncRepl options used for the HDB database. Without **rid** and **provider** which are automaticaly added based on LDAP_REPLICATION_HOSTS.  Defaults to `binddn="cn=admin,$LDAP_BASE_DN" bindmethod=simple credentials=$LDAP_ADMIN_PASSWORD searchbase="$LDAP_BASE_DN" type=refreshAndPersist interval=00:00:00:10 retry="60 +" timeout=1 starttls=critical`
 
 
-- **LDAP_REPLICATION_HOSTS**: list of replication hosts, must contains the current container hostname set by -h on docker run command. Defaults to :
-
-		- ldap://ldap.example.org
-		- ldap://ldap2.example.org
-
+- **LDAP_REPLICATION_HOSTS**: list of replication hosts, must contains the current container hostname set by --hostname on docker run command. Defaults to :
+```yaml
+	- ldap://ldap.example.org
+	- ldap://ldap2.example.org
+```
 	If you want to set this variable at docker run command add the tag `#PYTHON2BASH:` and convert the yaml in python :
 	If you want to set this variable at docker run command add the tag `#PYTHON2BASH:` and convert the yaml in python :
 
 
-		docker run --env LDAP_REPLICATION_HOSTS="#PYTHON2BASH:['ldap://ldap.example.org','ldap://ldap2.example.org']" -d osixia/openldap
+		docker run --env LDAP_REPLICATION_HOSTS="#PYTHON2BASH:['ldap://ldap.example.org','ldap://ldap2.example.org']" --detach osixia/openldap:1.1.0
 
 
 	To convert yaml to python online :
 	To convert yaml to python online :
 	http://yaml-online-parser.appspot.com/
 	http://yaml-online-parser.appspot.com/
 
 
+Other environment variables :
+- **LDAP_REMOVE_CONFIG_AFTER_SETUP**: delete config folder after setup. Defaults to `true`
+
+
 ### Set your own environment variables :
 ### Set your own environment variables :
 
 
 #### Use command line argument
 #### Use command line argument
 Environment variables can be set by adding the --env argument in the command line, for example :
 Environment variables can be set by adding the --env argument in the command line, for example :
 
 
 	docker run --env LDAP_ORGANISATION="My Compagny" --env LDAP_DOMAIN="my-compagny.com" \
 	docker run --env LDAP_ORGANISATION="My Compagny" --env LDAP_DOMAIN="my-compagny.com" \
-	--env LDAP_ADMIN_PASSWORD="JonSn0w" -d osixia/openldap
+	--env LDAP_ADMIN_PASSWORD="JonSn0w" --detach osixia/openldap:1.1.0
 
 
 Be aware that environment variable added in command line will be available at any time
 Be aware that environment variable added in command line will be available at any time
-in the container. In this example if an attacker manage to open a terminal in this container
+in the container. In this example if someone manage to open a terminal in this container
 he will be able to read the admin password in clear text from environment variables.
 he will be able to read the admin password in clear text from environment variables.
 
 
 #### Link environment file
 #### Link environment file
 
 
+	docker run --volume /data/my-env.yaml:/container/environment/01-custom/env.yaml \
+	--volume /data/my-env.yaml.setup:/container/environment/01-custom/env.yaml.setup \
+	--detach osixia/openldap:1.1.0
+
+Note: the container will try to delete the ***.yaml.setup** file after the first start so the file will also be deleted on the docker host.
+
+Use --volume /data/my-env.yaml.setup:/container/environment/01-custom/env.yaml.setup**:ro** to prevent that or set all variables in ***.yaml** file and don't mount ***.yaml.setup** file but all sensitive data will persists in container environment.
 
 
+#### Make your own image or extend this one
 
 
+This is the best solution if you have a private registry. Please refer to the [Advanced User Guide](#advanced-user-guide) just below.
 
 
-#### Make your own image
+## Advanced User Guide
 
 
+### Extend osixia/openldap:1.1.0 image
 
 
-Or by setting your own `env.yaml` file as a docker volume to `/container/environment/env.yaml`
+If you need to add your custom TLS certificate,   bootstrap config or environment files the easyest way is too extends this image.
 
 
-	docker run -v /data/my-env.yaml:/container/environment/env.yaml \
-	-d osixia/openldap
+Dockerfile example:
 
 
-## Manual build
+	FROM osixia/openldap:1.1.0
+	MAINTAINER Your Name <[email protected]>
+
+	ADD bootstrap /container/service/slapd/assets/config/bootstrap
+	ADD certs /container/service/slapd/assets/certs
+	ADD environment /container/environment/01-custom
+
+see complete example in **example/extend-osixia-openldap**
+
+### Make your own openldap image
 
 
 Clone this project :
 Clone this project :
 
 
@@ -246,13 +261,56 @@ Adapt Makefile, set your image NAME and VERSION, for example :
 	NAME = cool-guy/openldap
 	NAME = cool-guy/openldap
 	VERSION = 0.1.0
 	VERSION = 0.1.0
 
 
+Add your custom certificate, bootstrap ldif and environment files...
+
 Build your image :
 Build your image :
 
 
 	make build
 	make build
 
 
 Run your image :
 Run your image :
 
 
-	docker run -d cool-guy/openldap:0.1.0
+	docker run --detach cool-guy/openldap:0.1.0
+
+### Kubernetes
+
+Kubernetes is an open source system for managing containerized applications across multiple hosts, providing basic mechanisms for deployment, maintenance, and scaling of applications.
+
+More information:
+- http://kubernetes.io
+- https://github.com/kubernetes/kubernetes
+
+osixia-openldap kubernetes examples are available in **example/kubernetes**
+
+### Debug
+
+The container default log level is **info**.
+Available levels: `none`, `error`, `warning`, `info`, `debug` and `trace`.
+
+Example command to run the container in `debug` mode :
+
+	docker run --detach osixia/openldap:1.1.0 /container/tool/run --loglevel debug
+
+The tool `/container/tool/run` is provided by this image baseimage : osixia/light-baseimage
+
+### osixia/light-baseimage
+
+This image is base on osixia/light-baseimage.
+It uses the following features :
+
+- **cfssl** service to generate tls certificates
+- **log-helper** tool to print log messages based on the log level
+- **run** tool to init the container environment
+
+More info : https://github.com/osixia/docker-light-baseimage
+
+## Contributing
+
+If you find this image useful here's how you can help:
+
+- Send a pull request with your kickass new features and bug fixes
+- Help new users with [issues](https://github.com/osixia/docker-openldap/issues) they may encounter
+- Support the development of this image and star this repo ! ;)
+
 
 
 ## Tests
 ## Tests
 
 

+ 6 - 0
example/extend-osixia-openldap/Dockerfile

@@ -0,0 +1,6 @@
+FROM osixia/openldap:1.1.0-dev
+MAINTAINER Your Name <[email protected]>
+
+ADD bootstrap /container/service/slapd/assets/config/bootstrap
+ADD certs /container/service/slapd/assets/certs
+ADD environment /container/environment/01-custom

+ 12 - 0
example/extend-osixia-openldap/Makefile

@@ -0,0 +1,12 @@
+NAME = osixia/extend-osixia-openldap
+VERSION = 0.1.0
+
+.PHONY: all build build-nocache
+
+all: build
+
+build:
+	docker build -t $(NAME):$(VERSION) --rm .
+
+build-nocache:
+	docker build -t $(NAME):$(VERSION) --no-cache --rm .

+ 16 - 0
example/extend-osixia-openldap/bootstrap/ldif/billy.ldif

@@ -0,0 +1,16 @@
+dn: uid=billy,dc=example,dc=org
+changetype: add
+
+uid: billy
+cn: billy
+sn: 3
+objectClass: top
+objectClass: posixAccount
+objectClass: inetOrgPerson
+loginShell: /bin/bash
+homeDirectory: /home/billy
+uidNumber: 14583102
+gidNumber: 14564100
+userPassword: {SSHA}j3lBh1Seqe4rqF1+NuWmjhvtAni1JC5A
+mail: [email protected]
+gecos: Billy User

+ 833 - 0
example/extend-osixia-openldap/bootstrap/schema/asterisk.schema

@@ -0,0 +1,833 @@
+#
+# Copyright (c) 2007-2009 Suretec Systems Ltd. - <http://www.suretecsystems.com/>
+#
+# Version: 3.2.2
+#
+# Changes:
+
+# - Added AsteriskDialplan, AsteriskAccount and AsteriskMailbox objectClasses
+#   to allow standalone dialplan, account and mailbox entries (STRUCTURAL)
+# - Added new Fields
+#   * AstAccountLanguage, AstAccountTransport, AstAccountPromiscRedir,
+#   * AstAccountAccountCode, AstAccountSetVar, AstAccountAllowOverlap,
+#   * AstAccountVideoSupport, AstAccountIgnoreSDPVersion
+#   Removed redundant IPaddr (there's already IPAddress)
+# - Fixed typo - 13/08/2009
+# - https://issues.asterisk.org/view.php?id=13725 - 12/08/2009
+# - Added AsteriskVoiceMail Object class and AstAccountCallLimit attribute - 28/05/2009
+#   https://issues.asterisk.org/view.php?id=15155
+# - Added AstAccountLastQualifyMilliseconds - 28/05/2009
+#   https://issues.asterisk.org/view.php?id=15156
+# - https://issues.asterisk.org/view.php?id=12860 - 04/07/2008
+# - Fixed wrong DESC - 07/05/2008
+#
+# Author: Gavin Henry - <[email protected]>
+#         Michael Kromer - <[email protected]>
+#
+# Asterisk LDAP Schema
+#
+# Digium root OID (http://www.iana.org/assignments/enterprise-numbers)
+#
+#  1.3.6.1.4.1.22736
+#  1.3.6.1.4.1.22736.5      LDAP elements
+#  1.3.6.1.4.1.22736.5.4    Attribute Types
+#  1.3.6.1.4.1.22736.5.5    Object Classes
+#
+objectIdentifier AsteriskRoot 1.3.6.1.4.1.22736
+objectIdentifier AsteriskLDAP AsteriskRoot:5
+
+#############################################################################
+# Attribute group OIDs.  e.g.: objectIdentifier AstAttrType AsteriskLDAP:4
+#############################################################################
+objectIdentifier AstAttrType AsteriskLDAP:4
+
+#############################################################################
+# Attribute OIDs e.g.: objectIdentifier AstContext AstAttrType:1
+#############################################################################
+objectIdentifier AstContext AstAttrType:1
+objectIdentifier AstExtension AstAttrType:2
+objectIdentifier AstPriority AstAttrType:3
+objectIdentifier AstApplication AstAttrType:4
+objectIdentifier AstApplicationData AstAttrType:5
+objectIdentifier AstAccountAMAFlags AstAttrType:6
+objectIdentifier AstAccountCallerID AstAttrType:7
+objectIdentifier AstAccountContext AstAttrType:8
+objectIdentifier AstAccountMailbox AstAttrType:9
+objectIdentifier AstMD5secret AstAttrType:10
+objectIdentifier AstAccountDeny AstAttrType:11
+objectIdentifier AstAccountPermit AstAttrType:12
+objectIdentifier AstAccountQualify AstAttrType:13
+objectIdentifier AstAccountType AstAttrType:14
+objectIdentifier AstAccountDisallowedCodec AstAttrType:15
+objectIdentifier AstAccountExpirationTimestamp AstAttrType:16
+objectIdentifier AstAccountRegistrationContext AstAttrType:17
+objectIdentifier AstAccountRegistrationExten AstAttrType:18
+objectIdentifier AstAccountNoTransfer AstAttrType:19
+objectIdentifier AstAccountCallGroup AstAttrType:20
+objectIdentifier AstAccountCanReinvite AstAttrType:21
+objectIdentifier AstAccountDTMFMode AstAttrType:22
+objectIdentifier AstAccountFromUser AstAttrType:23
+objectIdentifier AstAccountFromDomain AstAttrType:24
+objectIdentifier AstAccountFullContact AstAttrType:25
+objectIdentifier AstAccountHost AstAttrType:26
+objectIdentifier AstAccountInsecure AstAttrType:27
+objectIdentifier AstAccountNAT AstAttrType:28
+objectIdentifier AstAccountPickupGroup AstAttrType:29
+objectIdentifier AstAccountPort AstAttrType:30
+objectIdentifier AstAccountRestrictCID AstAttrType:31
+objectIdentifier AstAccountRTPTimeout AstAttrType:32
+objectIdentifier AstAccountRTPHoldTimeout AstAttrType:33
+objectIdentifier AstAccountRealmedPassword AstAttrType:34
+objectIdentifier AstAccountAllowedCodec AstAttrType:35
+objectIdentifier AstAccountMusicOnHold AstAttrType:36
+objectIdentifier AstAccountCanCallForward AstAttrType:37
+objectIdentifier AstAccountSecret AstAttrType:38
+objectIdentifier AstAccountName AstAttrType:39
+objectIdentifier AstConfigFilename AstAttrType:40
+objectIdentifier AstConfigCategory AstAttrType:41
+objectIdentifier AstConfigCategoryMetric AstAttrType:42
+objectIdentifier AstConfigVariableName AstAttrType:43
+objectIdentifier AstConfigVariableValue AstAttrType:44
+objectIdentifier AstConfigCommented AstAttrType:45
+objectIdentifier AstAccountIPAddress AstAttrType:46
+objectIdentifier AstAccountDefaultUser AstAttrType:47
+objectIdentifier AstAccountRegistrationServer AstAttrType:48
+objectIdentifier AstAccountLastQualifyMilliseconds AstAttrType:49
+objectIdentifier AstAccountCallLimit AstAttrType:50
+objectIdentifier AstVoicemailMailbox AstAttrType:51
+objectIdentifier AstVoicemailPassword AstAttrType:52
+objectIdentifier AstVoicemailFullname AstAttrType:53
+objectIdentifier AstVoicemailEmail AstAttrType:54
+objectIdentifier AstVoicemailPager AstAttrType:55
+objectIdentifier AstVoicemailOptions AstAttrType:56
+objectIdentifier AstVoicemailTimestamp AstAttrType:57
+objectIdentifier AstVoicemailContext AstAttrType:58
+objectIdentifier AstAccountSubscribeContext AstAttrType:59
+objectIdentifier AstAccountUserAgent AstAttrType:61
+objectIdentifier AstAccountLanguage AstAttrType:62
+objectIdentifier AstAccountTransport AstAttrType:63
+objectIdentifier AstAccountPromiscRedir AstAttrType:64
+objectIdentifier AstAccountAccountCode AstAttrType:65
+objectIdentifier AstAccountSetVar AstAttrType:66
+objectIdentifier AstAccountAllowOverlap AstAttrType:67
+objectIdentifier AstAccountVideoSupport AstAttrType:68
+objectIdentifier AstAccountIgnoreSDPVersion AstAttrType:69
+
+
+#############################################################################
+# Object Class OIDs
+#############################################################################
+objectIdentifier AstObjectClass AsteriskLDAP:2
+objectIdentifier AsteriskExtension AstObjectClass:1
+objectIdentifier AsteriskIAXUser AstObjectClass:2
+objectIdentifier AsteriskSIPUser AstObjectClass:3
+objectIdentifier AsteriskConfig AstObjectClass:4
+objectIdentifier AsteriskVoiceMail AstObjectClass:5
+objectIdentifier AsteriskDialplan AstObjectClass:6
+objectIdentifier AsteriskAccount AstObjectClass:7
+objectIdentifier AsteriskMailbox AstObjectClass:8
+
+
+#############################################################################
+# attribute definitions
+#
+# OID (the first arg) comes from the objectIdentifier defined above
+#
+# NAME should be the same as objectIdentifier
+#
+# DESC should be the description of the attribute
+#
+# EQUALITY is the rule to use when doing a search/compare for an
+# attribute value.
+#
+# SUBSTR is the rule to use when doing a substring search (*foo*)
+#
+# SYNTAX is the syntax (i.e., type) of the attribute. We should
+# probably stick to syntaxes:
+#
+#       1.3.6.1.4.1.1466.115.121.1.15   -> directoryString (UTF-8 string)
+#       1.3.6.1.4.1.1466.115.121.1.26   -> IA5String (ASCII String)
+#       1.3.6.1.4.1.1466.115.121.1.27   -> integer (Integer value)
+#
+# SINGLE-VALUE should be present if only one instance of this
+# attribute is allowed within an entry.
+#
+# {32} is the allowed length
+#
+# e.g.:
+#
+# attributetype ( AstExample
+#    NAME ( 'AstExample' )
+#    DESC 'Asterisk Example Attribute'
+#    EQUALITY caseIgnoreMatch
+#    SUBSTR caseIgnoreSubstringsMatch
+#    SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{32}
+#    SINGLE-VALUE )
+#
+#############################################################################
+
+attributetype ( AstContext
+        NAME 'AstContext'
+        DESC 'Asterisk Context'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstExtension
+        NAME 'AstExtension'
+        DESC 'Asterisk Extension'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstPriority
+        NAME 'AstPriority'
+        DESC 'Asterisk Priority'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstApplication
+        NAME 'AstApplication'
+        DESC 'Asterisk Application'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstApplicationData
+        NAME 'AstApplicationData'
+        DESC 'Asterisk Application Data'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstAccountAMAFlags
+        NAME 'AstAccountAMAFlags'
+        DESC 'Asterisk Account AMA Flags'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstAccountCallerID
+        NAME 'AstAccountCallerID'
+        DESC 'Asterisk Account CallerID'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstAccountContext
+        NAME 'AstAccountContext'
+        DESC 'Asterisk Account Context'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstAccountMailbox
+        NAME 'AstAccountMailbox'
+        DESC 'Asterisk Account Mailbox'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstMD5secret
+        NAME 'AstMD5secret'
+        DESC 'Asterisk Account MD5 Secret'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstAccountDeny
+        NAME 'AstAccountDeny'
+        DESC 'Asterisk Account Deny'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstAccountPermit
+        NAME 'AstAccountPermit'
+        DESC 'Asterisk Account Permit'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstAccountQualify
+        NAME 'AstAccountQualify'
+        DESC 'Asterisk Account Qualify'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstAccountType
+        NAME 'AstAccountType'
+        DESC 'Asterisk Account Type'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstAccountDisallowedCodec
+        NAME 'AstAccountDisallowedCodec'
+        DESC 'Asterisk Account Disallowed Codec'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstAccountExpirationTimestamp
+        NAME 'AstAccountExpirationTimestamp'
+        DESC 'Asterisk Account Expiration Timestamp'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstAccountRegistrationContext
+        NAME 'AstAccountRegistrationContext'
+        DESC 'Asterisk Account Registration Context'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstAccountRegistrationExten
+        NAME 'AstAccountRegistrationExten'
+        DESC 'Asterisk Account Registration Extension'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstAccountNoTransfer
+        NAME 'AstAccountNoTransfer'
+        DESC 'Asterisk Account No Transfer'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstAccountCallGroup
+        NAME 'AstAccountCallGroup'
+        DESC 'Asterisk Account Call Group'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstAccountCanReinvite
+        NAME 'AstAccountCanReinvite'
+        DESC 'Asterisk Account Can Reinvite'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstAccountDTMFMode
+        NAME 'AstAccountDTMFMode'
+        DESC 'Asterisk Account DTMF Flags'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstAccountFromUser
+        NAME 'AstAccountFromUser'
+        DESC 'Asterisk Account From User'
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstAccountFromDomain
+        NAME 'AstAccountFromDomain'
+        DESC 'Asterisk Account From Domain'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstAccountFullContact
+        NAME 'AstAccountFullContact'
+        DESC 'Asterisk Account Full Contact'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstAccountHost
+        NAME 'AstAccountHost'
+        DESC 'Asterisk Account Host'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstAccountInsecure
+        NAME 'AstAccountInsecure'
+        DESC 'Asterisk Account Insecure'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstAccountNAT
+        NAME 'AstAccountNAT'
+        DESC 'Asterisk Account NAT'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstAccountPickupGroup
+        NAME 'AstAccountPickupGroup'
+        DESC 'Asterisk Account PickupGroup'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstAccountPort
+        NAME 'AstAccountPort'
+        DESC 'Asterisk Account Port'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstAccountRestrictCID
+        NAME 'AstAccountRestrictCID'
+        DESC 'Asterisk Account Restrict CallerID'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstAccountRTPTimeout
+        NAME 'AstAccountRTPTimeout'
+        DESC 'Asterisk Account RTP Timeout'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstAccountRTPHoldTimeout
+        NAME 'AstAccountRTPHoldTimeout'
+        DESC 'Asterisk Account RTP Hold Timeout'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstAccountRealmedPassword
+        NAME 'AstAccountRealmedPassword'
+        DESC 'Asterisk Account Realmed Password'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstAccountAllowedCodec
+        NAME 'AstAccountAllowedCodec'
+        DESC 'Asterisk Account Allowed Codec'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstAccountMusicOnHold
+        NAME 'AstAccountMusicOnHold'
+        DESC 'Asterisk Account Music On Hold'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstAccountCanCallForward
+        NAME 'AstAccountCanCallForward'
+        DESC 'Asterisk Account Can Call Forward'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstAccountSecret
+        NAME 'AstAccountSecret'
+        DESC 'Asterisk Account Secret'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstAccountName
+        NAME 'AstAccountName'
+        DESC 'Asterisk Account Username'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstConfigFilename
+        NAME 'AstConfigFilename'
+        DESC 'Asterisk LDAP Configuration Filename'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstConfigCategory
+        NAME 'AstConfigCategory'
+        DESC 'Asterisk LDAP Configuration Category'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstConfigCategoryMetric
+        NAME 'AstConfigCategoryMetric'
+        DESC 'Asterisk LDAP Configuration Category Metric'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstConfigVariableName
+        NAME 'AstConfigVariableName'
+        DESC 'Asterisk LDAP Configuration Variable Name'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstConfigVariableValue
+        NAME 'AstConfigVariableValue'
+        DESC 'Asterisk LDAP Configuration Variable Value'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstConfigCommented
+        NAME 'AstConfigCommented'
+        DESC 'Asterisk LDAP Configuration Commented'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstAccountIPAddress
+        NAME 'AstAccountIPAddress'
+        DESC 'Asterisk Account IP Address'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstAccountDefaultUser
+        NAME 'AstAccountDefaultUser'
+        DESC 'Asterisk Account Default User'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstAccountRegistrationServer
+        NAME 'AstAccountRegistrationServer'
+        DESC 'Asterisk Account Registration Server'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstAccountLastQualifyMilliseconds
+        NAME 'AstAccountLastQualifyMilliseconds'
+        DESC 'Asterisk Account Last Qualify Milliseconds'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstAccountCallLimit
+        NAME 'AstAccountCallLimit'
+        DESC 'Asterisk Account Call Limit'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstVoicemailMailbox
+        NAME 'AstVoicemailMailbox'
+        DESC 'Asterisk voicemail mailbox'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstVoicemailPassword
+        NAME 'AstVoicemailPassword'
+        DESC 'Asterisk voicemail password'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstVoicemailFullname
+        NAME 'AstVoicemailFullname'
+        DESC 'Asterisk voicemail fullname'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstVoicemailEmail
+        NAME 'AstVoicemailEmail'
+        DESC 'Asterisk voicemail email'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstVoicemailPager
+        NAME 'AstVoicemailPager'
+        DESC 'Asterisk voicemail pager'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstVoicemailOptions
+        NAME 'AstVoicemailOptions'
+        DESC 'Asterisk voicemail options'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstVoicemailTimestamp
+        NAME 'AstVoicemailTimestamp'
+        DESC 'Asterisk voicemail timestamp'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstVoicemailContext
+        NAME 'AstVoicemailContext'
+        DESC 'Asterisk voicemail context'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstAccountSubscribeContext
+        NAME 'AstAccountSubscribeContext'
+        DESC 'Asterisk subscribe context'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstAccountUserAgent
+        NAME 'AstAccountUserAgent'
+        DESC 'Asterisk account user context'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstAccountLanguage
+        NAME 'AstAccountLanguage'
+        DESC 'Asterisk account user language'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstAccountTransport
+        NAME 'AstAccountTransport'
+        DESC 'Asterisk account transport type'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstAccountPromiscRedir
+        NAME 'AstAccountPromiscRedir'
+        DESC 'Asterisk account promiscous redirects'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstAccountAccountCode
+        NAME 'AstAccountAccountCode'
+        DESC 'Asterisk account billing code'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstAccountSetVar
+        NAME 'AstAccountSetVar'
+        DESC 'Asterisk account setvar'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstAccountAllowOverlap
+        NAME 'AstAccountAllowOverlap'
+        DESC 'Asterisk account allow overlap dialing'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstAccountVideoSupport
+        NAME 'AstAccountVideoSupport'
+        DESC 'Asterisk account video support'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstAccountIgnoreSDPVersion
+        NAME 'AstAccountIgnoreSDPVersion'
+        DESC 'Asterisk account ignore SDP version'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+#############################################################################
+# Object Class definitions
+#
+# This is where to define the object classes. Object classes are used
+# to define which attribute MAY (optional) or MUST (required) belong
+# to an entry.
+#
+# Classes can be AUXILIARY or STRUCTURAL. An entry in the directory
+# must have one and only one structural class, but can have many
+# AUXILIARY classes.
+#
+#############################################################################
+
+objectclass ( AsteriskExtension
+    NAME 'AsteriskExtension'
+    DESC 'PBX Extension Information for Asterisk'
+    SUP top AUXILIARY
+    MUST cn
+    MAY (
+        AstContext $
+        AstExtension $
+        AstPriority $
+        AstApplication $
+        AstApplicationData
+    )
+    )
+
+#############################################################################
+#
+# AsteriskIAXUser and AsteriskSIPUser extend AsteriskExtension. These
+# represent real accounts in Asterisk.
+#
+# NOTE: They are defined as AUXILIARY in case they need to be mixed with an
+# existing directory deployment.
+#
+#############################################################################
+
+objectclass ( AsteriskIAXUser
+    NAME 'AsteriskIAXUser'
+    DESC 'IAX2 User information for Asterisk'
+    SUP AsteriskExtension AUXILIARY
+    MUST cn
+    MAY (
+        AstAccountAMAFlags $
+        AstAccountCallerID $
+        AstAccountContext $
+        AstAccountFullContact $
+        AstAccountHost $
+        AstAccountMailbox $
+        AstMD5secret $
+        AstAccountDeny $
+        AstAccountPermit $
+        AstAccountPort $
+        AstAccountQualify $
+        AstAccountType $
+        AstAccountLanguage $
+        AstAccountDisallowedCodec $
+        AstAccountExpirationTimestamp $
+        AstAccountRegistrationContext $
+        AstAccountRegistrationExten $
+        AstAccountNoTransfer $
+        AstAccountName $
+        AstAccountLastQualifyMilliseconds $
+        AstAccountCallLimit $
+        AstAccountSubscribeContext $
+        AstAccountIPAddress $
+        AstAccountUserAgent
+    )
+    )
+
+objectclass ( AsteriskSIPUser
+    NAME 'AsteriskSIPUser'
+    DESC 'SIP User information for Asterisk'
+    SUP AsteriskExtension AUXILIARY
+    MUST cn
+    MAY (
+        AstAccountAccountCode $
+        AstAccountAllowOverlap $
+        AstAccountAllowedCodec $
+        AstAccountAMAFlags $
+        AstAccountCallGroup $
+        AstAccountCallLimit $
+        AstAccountCallerID $
+        AstAccountCanCallForward $
+        AstAccountCanReinvite $
+        AstAccountContext $
+        AstAccountDTMFMode $
+        AstAccountDefaultUser $
+        AstAccountDeny $
+        AstAccountDisallowedCodec $
+        AstAccountExpirationTimestamp $
+        AstAccountFromDomain $
+        AstAccountFromUser $
+        AstAccountFullContact $
+        AstAccountHost $
+        AstAccountIgnoreSDPVersion $
+        AstAccountInsecure $
+        AstAccountIPAddress $
+        AstAccountLanguage $
+        AstAccountLastQualifyMilliseconds $
+        AstAccountMailbox $
+        AstAccountMusicOnHold $
+        AstAccountNAT $
+        AstAccountName $
+        AstAccountPermit $
+        AstAccountPickupGroup $
+        AstAccountPort $
+        AstAccountPromiscRedir $
+        AstAccountQualify $
+        AstAccountRTPHoldTimeout $
+        AstAccountRTPTimeout $
+        AstAccountRealmedPassword $
+        AstAccountRegistrationContext $
+        AstAccountRegistrationExten $
+        AstAccountRegistrationServer $
+        AstAccountRestrictCID $
+        AstAccountSecret $
+        AstAccountSetVar $
+        AstAccountSubscribeContext $
+        AstAccountTransport $
+        AstAccountType $
+        AstAccountUserAgent $
+        AstAccountVideoSupport
+    )
+    )
+
+#############################################################################
+#
+# AsteriskConfig and AsteriskVoiceMail extend AsteriskExtension. These
+# represent real accounts in Asterisk.
+#
+# NOTE: They are defined as AUXILIARY in case they need to be mixed with an
+# existing directory deployment.
+#
+#############################################################################
+
+objectclass ( AsteriskConfig
+    NAME 'AsteriskConfig'
+    DESC 'Asterisk configuration Information'
+    SUP top AUXILIARY
+    MUST cn
+    MAY (
+        AstConfigFilename $
+        AstConfigCategory $
+        AstConfigCategoryMetric $
+        AstConfigVariableName $
+        AstConfigVariableValue $
+        AstConfigCommented
+    )
+    )
+
+objectclass ( AsteriskVoiceMail
+    NAME 'AsteriskVoiceMail'
+    DESC 'Asterisk voicemail information'
+    SUP top AUXILIARY
+    MUST (
+    cn $
+    AstContext $
+    AstVoicemailMailbox $
+    AstVoicemailPassword
+    )
+    MAY (
+    AstVoicemailFullname $
+    AstVoicemailEmail $
+    AstVoicemailPager $
+    AstVoicemailOptions $
+    AstVoicemailTimestamp $
+    AstVoicemailContext
+    )
+    )
+
+objectClass (
+	AsteriskDialplan
+	NAME 'AsteriskDialplan'
+	DESC 'Asterisk Dialplan Information'
+	SUP top STRUCTURAL
+	MUST ( AstExtension ) )
+
+objectClass (
+	AsteriskAccount
+	NAME 'AsteriskAccount'
+	DESC 'Asterisk Account Information'
+	SUP top STRUCTURAL
+	MUST ( AstAccountName ) )
+
+objectClass (
+	AsteriskMailbox
+	NAME 'AsteriskMailbox'
+	DESC 'Asterisk Mailbox Information'
+	SUP top STRUCTURAL
+	MUST ( AstVoicemailMailbox ) )

+ 270 - 0
example/extend-osixia-openldap/bootstrap/schema/sendmail.schema

@@ -0,0 +1,270 @@
+# Copyright (c) 2000-2002, 2005 Sendmail, Inc. and its suppliers.
+#	All rights reserved.
+#
+# By using this file, you agree to the terms and conditions set
+# forth in the LICENSE file which can be found at the top level of
+# the sendmail distribution.
+#
+# $Id: sendmail.schema,v 8.22 2005/09/16 20:18:14 ca Exp $
+
+# Note that this schema is experimental at this point as it has had little
+# public review.  Therefore, it may change in future versions.  Feedback
+# via [email protected] is encouraged (replace YYYY with
+# the current year, e.g., 2005).
+
+# OID arcs for Sendmail
+# enterprise:		1.3.6.1.4.1
+# sendmail:		enterprise.6152
+# sendmail-at:		sendmail.3.1
+# sendmail-oc:		sendmail.3.2
+
+###########################################################################
+#
+# The Sendmail MTA attributes and objectclass
+#
+###########################################################################
+
+# attribute sendmailMTACluster	cis
+attributetype ( 1.3.6.1.4.1.6152.10.3.1.10
+	NAME 'sendmailMTACluster'
+	DESC 'cluster name associated with a set of MTAs'
+	EQUALITY caseIgnoreIA5Match
+	SUBSTR caseIgnoreIA5SubstringsMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )
+
+# attribute sendmailMTAHost	cis
+attributetype ( 1.3.6.1.4.1.6152.10.3.1.11
+	NAME 'sendmailMTAHost'
+	DESC 'host name associated with a MTA cluster'
+	EQUALITY caseIgnoreIA5Match
+	SUBSTR caseIgnoreIA5SubstringsMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )
+
+#objectClass sendmailMTA
+#	requires
+#		objectClass
+#	allows
+#		sendmailMTACluster,
+#		sendmailMTAHost,
+#		Description
+
+objectclass ( 1.3.6.1.4.1.6152.10.3.2.10
+	NAME 'sendmailMTA'
+	SUP top STRUCTURAL
+	DESC 'Sendmail MTA definition'
+	MAY ( sendmailMTACluster $ sendmailMTAHost $ Description ) )
+
+###########################################################################
+#
+# The Sendmail MTA shared attributes
+#
+###########################################################################
+
+# attribute sendmailMTAKey	cis
+attributetype ( 1.3.6.1.4.1.6152.10.3.1.13
+	NAME 'sendmailMTAKey'
+	DESC 'key (left hand side) of an aliases or map entry'
+	EQUALITY caseIgnoreMatch
+	SUBSTR caseIgnoreSubstringsMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
+
+###########################################################################
+#
+# The Sendmail MTA Map attributes and objectclasses
+#
+###########################################################################
+
+# attribute sendmailMTAMapName	cis
+attributetype ( 1.3.6.1.4.1.6152.10.3.1.14
+	NAME 'sendmailMTAMapName'
+	DESC 'identifier for the particular map'
+	EQUALITY caseIgnoreMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} SINGLE-VALUE )
+
+# attribute sendmailMTAMapValue	cis
+attributetype ( 1.3.6.1.4.1.6152.10.3.1.16
+	NAME 'sendmailMTAMapValue'
+	DESC 'value (right hand side) of a map entry'
+	EQUALITY caseIgnoreMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
+
+# attribute sendmailMTAMapSearch cis
+attributetype ( 1.3.6.1.4.1.6152.10.3.1.24
+	NAME 'sendmailMTAMapSearch'
+	DESC 'recursive search for values of a map entry'
+	EQUALITY caseExactMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
+
+# attribute sendmailMTAMapURL cis
+attributetype ( 1.3.6.1.4.1.6152.10.3.1.25
+	NAME 'sendmailMTAMapURL'
+	DESC 'recursive search URL for values of a map entry'
+	EQUALITY caseExactMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
+
+#objectClass sendmailMTAMap
+#	requires
+#		objectClass,
+#		sendmailMTAMapName,
+#	allows
+#		sendmailMTACluster,
+#		sendmailMTAHost,
+#		Description
+
+objectclass ( 1.3.6.1.4.1.6152.10.3.2.11
+	NAME 'sendmailMTAMap'
+	SUP sendmailMTA STRUCTURAL
+	DESC 'Sendmail MTA map definition'
+	MUST sendmailMTAMapName
+	MAY ( sendmailMTACluster $ sendmailMTAHost $ Description ) )
+
+#objectClass sendmailMTAObject
+#	requires
+#		objectClass,
+#		sendmailMTAMapName,
+#		sendmailMTAKey,
+#	allows
+#		sendmailMTACluster,
+#		sendmailMTAHost,
+#		sendmailMTAMapValue,
+#		sendmailMTAMapSearch,
+#		sendmailMTAMapURL,
+#		Description
+
+objectclass ( 1.3.6.1.4.1.6152.10.3.2.12
+	NAME 'sendmailMTAMapObject'
+	SUP sendmailMTAMap STRUCTURAL
+	DESC 'Sendmail MTA map object'
+	MUST ( sendmailMTAMapName $ sendmailMTAKey )
+	MAY ( sendmailMTACluster $ sendmailMTAHost $
+		sendmailMTAMapValue $ sendmailMTAMapSearch $
+		sendmailMTAMapURL $ Description ) )
+
+
+###########################################################################
+#
+# The Sendmail MTA Alias attributes and objectclasses
+#
+###########################################################################
+
+# attribute sendmailMTAAliasGrouping	cis
+attributetype ( 1.3.6.1.4.1.6152.10.3.1.18
+	NAME 'sendmailMTAAliasGrouping'
+	DESC 'name that identifies a particular aliases grouping'
+	EQUALITY caseIgnoreIA5Match
+	SUBSTR caseIgnoreIA5SubstringsMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )
+
+# attribute sendmailMTAAliasValue	cis
+attributetype ( 1.3.6.1.4.1.6152.10.3.1.20
+	NAME 'sendmailMTAAliasValue'
+	DESC 'value (right hand side) of an alias'
+	EQUALITY caseIgnoreMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+# attribute sendmailMTAAliasSearch cis
+attributetype ( 1.3.6.1.4.1.6152.10.3.1.26
+	NAME 'sendmailMTAAliasSearch'
+	DESC 'recursive search for values of an alias'
+	EQUALITY caseExactMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
+
+# attribute sendmailMTAAliasURL cis
+attributetype ( 1.3.6.1.4.1.6152.10.3.1.27
+	NAME 'sendmailMTAAliasURL'
+	DESC 'recursive search URL for values of an alias'
+	EQUALITY caseExactMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
+
+#objectClass sendmailMTAAlias
+#	requires
+#		objectClass,
+#	allows
+#		sendmailMTAAliasGrouping,
+#		sendmailMTACluster,
+#		sendmailMTAHost,
+#		Description
+
+objectclass ( 1.3.6.1.4.1.6152.10.3.2.13
+	NAME 'sendmailMTAAlias'
+	SUP sendmailMTA STRUCTURAL
+	DESC 'Sendmail MTA alias definition'
+	MAY ( sendmailMTAAliasGrouping $
+		sendmailMTACluster $ sendmailMTAHost $ Description ) )
+
+#objectClass sendmailMTAAliasObject
+#	requires
+#		objectClass,
+#		sendmailMTAKey,
+#	allows
+#		sendmailMTAAliasGrouping,
+#		sendmailMTACluster,
+#		sendmailMTAHost,
+#		sendmailMTAAliasValue,
+#		sendmailMTAAliasSearch,
+#		sendmailMTAAliasURL,
+#		Description
+
+objectclass ( 1.3.6.1.4.1.6152.10.3.2.14
+	NAME 'sendmailMTAAliasObject'
+	SUP sendmailMTAAlias STRUCTURAL
+	DESC 'Sendmail MTA alias object'
+	MUST sendmailMTAKey
+	MAY ( sendmailMTAAliasGrouping $ sendmailMTACluster $
+		sendmailMTAHost $ sendmailMTAAliasValue $
+		sendmailMTAAliasSearch $ sendmailMTAAliasURL $ Description ) )
+
+###########################################################################
+#
+# The Sendmail MTA Class attributes and objectclass
+#
+###########################################################################
+
+# attribute sendmailMTAClassName	cis
+attributetype ( 1.3.6.1.4.1.6152.10.3.1.22
+	NAME 'sendmailMTAClassName'
+	DESC 'identifier for the class'
+	EQUALITY caseIgnoreMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} SINGLE-VALUE )
+
+# attribute sendmailMTAClassValue	cis
+attributetype ( 1.3.6.1.4.1.6152.10.3.1.23
+	NAME 'sendmailMTAClassValue'
+	DESC 'member of a class'
+	EQUALITY caseIgnoreMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+# attribute sendmailMTAClassSearch cis
+attributetype ( 1.3.6.1.4.1.6152.10.3.1.28
+	NAME 'sendmailMTAClassSearch'
+	DESC 'recursive search for members of a class'
+	EQUALITY caseExactMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
+
+# attribute sendmailMTAClassURL cis
+attributetype ( 1.3.6.1.4.1.6152.10.3.1.29
+	NAME 'sendmailMTAClassURL'
+	DESC 'recursive search URL for members of a class'
+	EQUALITY caseExactMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
+
+#objectClass sendmailMTAClass
+#	requires
+#		objectClass,
+#		sendmailMTAClassName,
+#	allows
+#		sendmailMTACluster,
+#		sendmailMTAHost,
+#		sendmailMTAClassValue,
+#		sendmailMTAClassSearch,
+#		sendmailMTAClassURL,
+#		Description
+
+objectclass ( 1.3.6.1.4.1.6152.10.3.2.15
+	NAME 'sendmailMTAClass'
+	SUP sendmailMTA STRUCTURAL
+	DESC 'Sendmail MTA class definition'
+	MUST sendmailMTAClassName
+	MAY ( sendmailMTACluster $ sendmailMTAHost $
+		sendmailMTAClassValue $ sendmailMTAClassSearch $
+		sendmailMTAClassURL $ Description ) )

+ 18 - 0
example/extend-osixia-openldap/certs/ca.crt

@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC0zCCAlmgAwIBAgIUCfQ+m0pgZ/BjYAJvxrn/bdGNZokwCgYIKoZIzj0EAwMw
+gZYxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxBMUEgQ2FyIFdhc2gxJDAiBgNVBAsT
+G0luZm9ybWF0aW9uIFRlY2hub2xvZ3kgRGVwLjEUMBIGA1UEBxMLQWxidXF1ZXJx
+dWUxEzARBgNVBAgTCk5ldyBNZXhpY28xHzAdBgNVBAMTFmRvY2tlci1saWdodC1i
+YXNlaW1hZ2UwHhcNMTUxMjIzMTM1MzAwWhcNMjAxMjIxMTM1MzAwWjCBljELMAkG
+A1UEBhMCVVMxFTATBgNVBAoTDEExQSBDYXIgV2FzaDEkMCIGA1UECxMbSW5mb3Jt
+YXRpb24gVGVjaG5vbG9neSBEZXAuMRQwEgYDVQQHEwtBbGJ1cXVlcnF1ZTETMBEG
+A1UECBMKTmV3IE1leGljbzEfMB0GA1UEAxMWZG9ja2VyLWxpZ2h0LWJhc2VpbWFn
+ZTB2MBAGByqGSM49AgEGBSuBBAAiA2IABMZf/12pupAgl8Sm+j8GmjNeNbSFAZWW
+oTmIvf2Mu4LWPHy4bTldkQgHUbBpT3xWz8f0lB/ru7596CHsGoL2A28hxuclq5hb
+Ux1yrIt3bJIY3TuiX25HGTe6kGCJPB1aLaNmMGQwDgYDVR0PAQH/BAQDAgEGMBIG
+A1UdEwEB/wQIMAYBAf8CAQIwHQYDVR0OBBYEFE+l6XolXDAYnGLTl4W6ULKHrm74
+MB8GA1UdIwQYMBaAFE+l6XolXDAYnGLTl4W6ULKHrm74MAoGCCqGSM49BAMDA2gA
+MGUCMQCXLZj8okyxW6UTL7hribUUbu63PbjuwIXnwi420DdNsvA9A7fcQEXScWFL
+XAGC8rkCMGcqwXZPSRfwuI9r+R11gTrP92hnaVxs9sjRikctpkQpOyNlIXFPopFK
+8FdfWPypvA==
+-----END CERTIFICATE-----

+ 18 - 0
example/extend-osixia-openldap/certs/cert.crt

@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC8TCCAnegAwIBAgIIXM3vfP16npQwCgYIKoZIzj0EAwMwgZYxCzAJBgNVBAYT
+AlVTMRUwEwYDVQQKEwxBMUEgQ2FyIFdhc2gxJDAiBgNVBAsTG0luZm9ybWF0aW9u
+IFRlY2hub2xvZ3kgRGVwLjEUMBIGA1UEBxMLQWxidXF1ZXJxdWUxEzARBgNVBAgT
+Ck5ldyBNZXhpY28xHzAdBgNVBAMTFmRvY2tlci1saWdodC1iYXNlaW1hZ2UwHhcN
+MTYwMTEwMDk1OTAwWhcNMTcwMTA5MDk1OTAwWjCBjDELMAkGA1UEBhMCVVMxFTAT
+BgNVBAoTDEExQSBDYXIgV2FzaDEkMCIGA1UECxMbSW5mb3JtYXRpb24gVGVjaG5v
+bG9neSBEZXAuMRQwEgYDVQQHEwtBbGJ1cXVlcnF1ZTETMBEGA1UECBMKTmV3IE1l
+eGljbzEVMBMGA1UEAxMMZTNkMTNlZmQ5YjMxMHYwEAYHKoZIzj0CAQYFK4EEACID
+YgAElkKdHmSbyRwpEGkaMW4Hq9XHpEWLnet7mkqpigQMCMNhuUKLThKYWOm8ZLK3
+Yo21jeb/dXF2LiXgd/Jjaenas3KXkb/FMJESQVTvZ3dwcQwOgyEpCTbjs2GSbiK7
+1JuNo4GZMIGWMA4GA1UdDwEB/wQEAwIAoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYI
+KwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUtXICfw5YqIkZi83qxOpB
+P5UaHXcwHwYDVR0jBBgwFoAUT6XpeiVcMBicYtOXhbpQsoeubvgwFwYDVR0RBBAw
+DoIMZTNkMTNlZmQ5YjMxMAoGCCqGSM49BAMDA2gAMGUCMQC20jjmVWusnspeGSOr
+Yk+pWNdbTKzNLaU8mR3X2gCs07xrws6cFJBdx/lx8KxE05YCMEaD5kdea/HkaBzy
+5xJZJAuIMpj56AR3J4od9aa3x74NDpgOObRDc4Y7ErAWqjsf3A==
+-----END CERTIFICATE-----

+ 6 - 0
example/extend-osixia-openldap/certs/cert.key

@@ -0,0 +1,6 @@
+-----BEGIN EC PRIVATE KEY-----
+MIGkAgEBBDAXhGbcS1lHXUJ6cvJZHlm/nHmjJ+wzj+REhgIlQUhf+mDELlwgJEJo
+Hnag8Ow0xMygBwYFK4EEACKhZANiAASWQp0eZJvJHCkQaRoxbger1cekRYud63ua
+SqmKBAwIw2G5QotOEphY6bxksrdijbWN5v91cXYuJeB38mNp6dqzcpeRv8UwkRJB
+VO9nd3BxDA6DISkJNuOzYZJuIrvUm40=
+-----END EC PRIVATE KEY-----

+ 8 - 0
example/extend-osixia-openldap/certs/dhparam.pem

@@ -0,0 +1,8 @@
+-----BEGIN DH PARAMETERS-----
+MIIBCAKCAQEA7adhygsX/CvbcQBlSEKBmm0D0+hVfIttcftyFTuDPNok4yDJUBUF
+zzc7X/i3PUMzANhShBrngBaXbOhVk3QcjMC623TPhFmILx0r236+aQEUGnlwN73M
+RUFM6EblYgH4+E4nv+JLwzHdO72+qMAd92rtzVMiaDlCWghH6wdAFoasTsT6Posc
+F5T8WCkzFAZeVhNGRKPP6k3l2BjvRJzkwYMMJrxaIYznMEK6H5CYIqZcpeAB3d2B
+NaZXLxFCemLrSS16UHrH1modEe8yjrOaE5+ZesGAA9onsNRZkAJp0x/pRaO/+rHn
+Q5QVCQCzxY16UsLzH0q/P80xPMU7BMoocwIBAg==
+-----END DH PARAMETERS-----

+ 10 - 0
example/extend-osixia-openldap/environment/my-env.yaml

@@ -0,0 +1,10 @@
+# This is the default image configuration file
+# These values will persists in container environment.
+
+# All environment variables used after the container first start
+# must be defined here.
+# more information : https://github.com/osixia/docker-light-baseimage
+
+# General container configuration
+# see table 5.1 in http://www.openldap.org/doc/admin24/slapdconf2.html for the available log levels.
+LDAP_LOG_LEVEL: 0

+ 45 - 0
example/extend-osixia-openldap/environment/my-env.yaml.setup

@@ -0,0 +1,45 @@
+# This is the default image startup configuration file
+# this file define environment variables used during the container **first start** in **startup scripts**.
+
+# This file is deleted right after startup scripts are processed for the first time,
+# after that all theses values will not be available in the container environment.
+# That helps to keep your container configuration secret.
+# more information : https://github.com/osixia/docker-light-baseimage
+
+# Required and used for new ldap server only
+LDAP_ORGANISATION: Example Inc.
+LDAP_DOMAIN: example.org
+LDAP_ADMIN_PASSWORD: Adm1n!
+LDAP_CONFIG_PASSWORD: c0nfig
+
+LDAP_READONLY_USER: true
+LDAP_READONLY_USER_USERNAME: readonly
+LDAP_READONLY_USER_PASSWORD: passwr0rd!
+
+# Tls
+LDAP_TLS: true
+LDAP_TLS_CRT_FILENAME: cert.crt
+LDAP_TLS_KEY_FILENAME: cert.key
+LDAP_TLS_CA_CRT_FILENAME: ca.crt
+
+LDAP_TLS_CIPHER_SUITE: SECURE256:-VERS-SSL3.0
+LDAP_TLS_PROTOCOL_MIN: 3.1
+LDAP_TLS_VERIFY_CLIENT: never
+
+# Replication
+LDAP_REPLICATION: false
+# variables $LDAP_BASE_DN, $LDAP_ADMIN_PASSWORD, $LDAP_CONFIG_PASSWORD
+# are automaticaly replaced at run time
+
+# if you want to add replication to an existing ldap
+# adapt LDAP_REPLICATION_CONFIG_SYNCPROV and LDAP_REPLICATION_HDB_SYNCPROV to your configuration
+# avoid using $LDAP_BASE_DN, $LDAP_ADMIN_PASSWORD and $LDAP_CONFIG_PASSWORD variables
+LDAP_REPLICATION_CONFIG_SYNCPROV: binddn="cn=admin,cn=config" bindmethod=simple credentials=$LDAP_CONFIG_PASSWORD searchbase="cn=config" type=refreshAndPersist retry="60 +" timeout=1 starttls=critical
+LDAP_REPLICATION_HDB_SYNCPROV: binddn="cn=admin,$LDAP_BASE_DN" bindmethod=simple credentials=$LDAP_ADMIN_PASSWORD searchbase="$LDAP_BASE_DN" type=refreshAndPersist interval=00:00:00:10 retry="60 +" timeout=1 starttls=critical
+LDAP_REPLICATION_HOSTS:
+  - ldap://ldap.example.org # The order must be the same on all ldap servers
+  - ldap://ldap2.example.org
+
+
+# Remove config after setup
+LDAP_REMOVE_CONFIG_AFTER_SETUP: false

+ 98 - 0
example/kubernetes/simple/ldap-rc.yaml

@@ -0,0 +1,98 @@
+apiVersion: v1
+kind: ReplicationController
+metadata:
+  name: ldap-controller
+  labels:
+    app: ldap
+spec:
+  replicas: 1
+  selector:
+    app: ldap
+  template:
+    metadata:
+      labels:
+        app: ldap
+    spec:
+      containers:
+        - name: ldap
+          image: osixia/openldap:1.1.0
+          volumeMounts:
+            - name: ldap-data
+              mountPath: /var/lib/ldap
+            - name: ldap-config
+              mountPath: /etc/ldap/slapd.d
+            - name: ldap-certs
+              mountPath: /container/service/slapd/assets/certs
+          ports:
+            - containerPort: 389
+              name: openldap
+          env:
+            - name: LDAP_LOG_LEVEL
+              value: "0"
+            - name: LDAP_ORGANISATION
+              value: "Example Inc."
+            - name: LDAP_DOMAIN
+              value: "example.org"
+            - name: LDAP_ADMIN_PASSWORD
+              value: "admin"
+            - name: LDAP_CONFIG_PASSWORD
+              value: "config"
+            - name: LDAP_READONLY_USER
+              value: "false"
+            - name: LDAP_READONLY_USER_USERNAME
+              value: "readonly"
+            - name: LDAP_READONLY_USER_PASSWORD
+              value: "readonly"
+            - name: LDAP_TLS
+              value: "true"
+            - name: LDAP_TLS_CRT_FILENAME
+              value: "ldap.crt"
+            - name: LDAP_TLS_KEY_FILENAME
+              value: "ldap.key"
+            - name: LDAP_TLS_CA_CRT_FILENAME
+              value: "ca.crt"
+            - name: LDAP_TLS_CIPHER_SUITE
+              value: "SECURE256:-VERS-SSL3.0"
+            - name: LDAP_TLS_PROTOCOL_MIN
+              value: "3.1"
+            - name: LDAP_TLS_VERIFY_CLIENT
+              value: "demand"
+            - name: LDAP_REPLICATION
+              value: "false"
+            - name: LDAP_REPLICATION_CONFIG_SYNCPROV
+              value: "binddn=\"cn=admin,cn=config\" bindmethod=simple credentials=$LDAP_CONFIG_PASSWORD searchbase=\"cn=config\" type=refreshAndPersist retry=\"60 +\" timeout=1 starttls=critical"
+            - name: LDAP_REPLICATION_HDB_SYNCPROV
+              value: "binddn=\"cn=admin,$LDAP_BASE_DN\" bindmethod=simple credentials=$LDAP_ADMIN_PASSWORD searchbase=\"$LDAP_BASE_DN\" type=refreshAndPersist interval=00:00:00:10 retry=\"60 +\" timeout=1 starttls=critical"
+            - name: LDAP_REPLICATION_HOSTS
+              value: "#PYTHON2BASH:['ldap://ldap-one-service', 'ldap://ldap-two-service']"
+            - name: LDAP_REMOVE_CONFIG_AFTER_SETUP
+              value: "true"
+        - name: ldap-backup
+          image: osixia/openldap-backup:0.1.7
+          volumeMounts:
+            - name: ldap-data
+              mountPath: /var/lib/ldap
+            - name: ldap-config
+              mountPath: /etc/ldap/slapd.d
+            - name: ldap-backup
+              mountPath: /data/backup
+          env:
+            - name: LDAP_BACKUP_CONFIG_CRON_EXP
+              value: "15 1 * * *"
+            - name: LDAP_BACKUP_DATA_CRON_EXP
+              value: "20 1 * * *"
+            - name: LDAP_BACKUP_TTL
+              value: "15"
+      volumes:
+        - name: ldap-data
+          hostPath:
+            path: "/data/ldap/db"
+        - name: ldap-config
+          hostPath:
+            path: "/data/ldap/config"
+        - name: ldap-backup
+          hostPath:
+            path: "/data/ldap/backup"
+        - name: ldap-certs
+          hostPath:
+            path: "/data/ldap/certs"

+ 11 - 0
example/kubernetes/simple/ldap-svc.yaml

@@ -0,0 +1,11 @@
+apiVersion: v1
+kind: Service
+metadata:
+  labels:
+    app: ldap
+  name: ldap-service
+spec:
+  ports:
+    - port: 389
+  selector:
+    app: ldap

+ 3 - 4
image/Dockerfile

@@ -10,6 +10,7 @@ RUN groupadd -r openldap && useradd -r -g openldap openldap
 
 
 # Install OpenLDAP, ldap-utils and cfssl from baseimage and remove default ldap db
 # Install OpenLDAP, ldap-utils and cfssl from baseimage and remove default ldap db
 # https://github.com/osixia/docker-light-baseimage/blob/stable/image/tool/install-service-available
 # https://github.com/osixia/docker-light-baseimage/blob/stable/image/tool/install-service-available
+# https://github.com/osixia/docker-light-baseimage/blob/stable/image/service-available/.cfssl
 RUN apt-get -y update \
 RUN apt-get -y update \
     && /container/tool/install-service-available cfssl \
     && /container/tool/install-service-available cfssl \
 	  && LC_ALL=C DEBIAN_FRONTEND=noninteractive apt-get install -y --force-yes --no-install-recommends \
 	  && LC_ALL=C DEBIAN_FRONTEND=noninteractive apt-get install -y --force-yes --no-install-recommends \
@@ -19,10 +20,8 @@ RUN apt-get -y update \
 # Add service directory to /container/service
 # Add service directory to /container/service
 ADD service /container/service
 ADD service /container/service
 
 
-# Use baseimage install-service script and clean all
-# https://github.com/osixia/docker-light-baseimage/blob/stable/image/tool/install-service
-RUN /container/tool/install-service \
-    && apt-get clean \
+# Clean tmp and apt-get files
+RUN apt-get clean \
     && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
     && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
 
 
 # Add default env variables
 # Add default env variables

+ 4 - 0
image/environment/default.yaml.setup

@@ -39,3 +39,7 @@ LDAP_REPLICATION_HDB_SYNCPROV: binddn="cn=admin,$LDAP_BASE_DN" bindmethod=simple
 LDAP_REPLICATION_HOSTS:
 LDAP_REPLICATION_HOSTS:
   - ldap://ldap.example.org # The order must be the same on all ldap servers
   - ldap://ldap.example.org # The order must be the same on all ldap servers
   - ldap://ldap2.example.org
   - ldap://ldap2.example.org
+
+
+# Remove config after setup
+LDAP_REMOVE_CONFIG_AFTER_SETUP: true

+ 99 - 66
image/service/slapd/container-start.sh

@@ -1,8 +1,9 @@
 #!/bin/bash -e
 #!/bin/bash -e
+set -o pipefail
 
 
-FIRST_START_SETUP_DONE="/container/run/state/slapd-first-start-setup-done"
-WAS_STARTED_WITH_TLS="/etc/ldap/slapd.d/docker-openldap-was-started-with-tls"
-WAS_STARTED_WITH_REPLICATION="/etc/ldap/slapd.d/docker-openldap-was-started-with-replication"
+# set -x (bash debug) if log level is trace
+# https://github.com/osixia/docker-light-baseimage/blob/stable/image/tool/log-helper
+log-helper level eq trace && set -x
 
 
 # Reduce maximum number of number of open file descriptors to 1024
 # Reduce maximum number of number of open file descriptors to 1024
 # otherwise slapd consumes two orders of magnitude more of RAM
 # otherwise slapd consumes two orders of magnitude more of RAM
@@ -13,10 +14,19 @@ ulimit -n 1024
 chown -R openldap:openldap /var/lib/ldap
 chown -R openldap:openldap /var/lib/ldap
 chown -R openldap:openldap /etc/ldap
 chown -R openldap:openldap /etc/ldap
 chown -R openldap:openldap ${SERVICE_DIR}/slapd
 chown -R openldap:openldap ${SERVICE_DIR}/slapd
+# the SERVICE_DIR variable is set by /container/tool/run
+# more info: https://github.com/osixia/docker-light-baseimage
+
+FIRST_START_SETUP_DONE="/container/run/state/slapd-first-start-setup-done"
+WAS_STARTED_WITH_TLS="/etc/ldap/slapd.d/docker-openldap-was-started-with-tls"
+WAS_STARTED_WITH_REPLICATION="/etc/ldap/slapd.d/docker-openldap-was-started-with-replication"
 
 
 # container first start
 # container first start
 if [ ! -e "$FIRST_START_SETUP_DONE" ]; then
 if [ ! -e "$FIRST_START_SETUP_DONE" ]; then
 
 
+  #
+  # Helpers
+  #
   function get_ldap_base_dn() {
   function get_ldap_base_dn() {
     LDAP_BASE_DN=""
     LDAP_BASE_DN=""
     IFS='.' read -ra LDAP_BASE_DN_TABLE <<< "$LDAP_DOMAIN"
     IFS='.' read -ra LDAP_BASE_DN_TABLE <<< "$LDAP_DOMAIN"
@@ -44,6 +54,8 @@ if [ ! -e "$FIRST_START_SETUP_DONE" ]; then
     local LDAP_KEY=$3
     local LDAP_KEY=$3
     local DH_PARAM=$4
     local DH_PARAM=$4
 
 
+    # generate a certificate and key with cfssl tool if LDAP_CRT and LDAP_KEY files don't exists
+    # https://github.com/osixia/docker-light-baseimage/blob/stable/image/service-available/.cfssl/assets/tool/cfssl-helper
     cfssl-helper ldap $LDAP_CRT $LDAP_KEY $CA_CRT
     cfssl-helper ldap $LDAP_CRT $LDAP_KEY $CA_CRT
 
 
     # create DHParamFile if not found
     # create DHParamFile if not found
@@ -54,14 +66,19 @@ if [ ! -e "$FIRST_START_SETUP_DONE" ]; then
     chown -R openldap:openldap ${SERVICE_DIR}/slapd
     chown -R openldap:openldap ${SERVICE_DIR}/slapd
   }
   }
 
 
+  #
+  # Global variables
+  #
   BOOTSTRAP=false
   BOOTSTRAP=false
 
 
-  # database and config directory are empty -> set bootstrap config
+  #
+  # database and config directory are empty
+  # setup bootstrap config - Part 1
+  #
   if [ -z "$(ls -A /var/lib/ldap)" ] && [ -z "$(ls -A /etc/ldap/slapd.d)" ]; then
   if [ -z "$(ls -A /var/lib/ldap)" ] && [ -z "$(ls -A /etc/ldap/slapd.d)" ]; then
 
 
     BOOTSTRAP=true
     BOOTSTRAP=true
-    echo "database and config directory are empty"
-    echo "-> set bootstrap config"
+    log-helper info "Database and config directory are empty"
 
 
     cat <<EOF | debconf-set-selections
     cat <<EOF | debconf-set-selections
 slapd slapd/internal/generated_adminpw password ${LDAP_ADMIN_PASSWORD}
 slapd slapd/internal/generated_adminpw password ${LDAP_ADMIN_PASSWORD}
@@ -81,60 +98,65 @@ EOF
 
 
     dpkg-reconfigure -f noninteractive slapd
     dpkg-reconfigure -f noninteractive slapd
 
 
+  #
+  # Error: the database directory (/var/lib/ldap) is empty but not the config directory (/etc/ldap/slapd.d)
+  #
   elif [ -z "$(ls -A /var/lib/ldap)" ] && [ ! -z "$(ls -A /etc/ldap/slapd.d)" ]; then
   elif [ -z "$(ls -A /var/lib/ldap)" ] && [ ! -z "$(ls -A /etc/ldap/slapd.d)" ]; then
-    echo "Error: the database directory (/var/lib/ldap) is empty but not the config directory (/etc/ldap/slapd.d)"
+    log-helper error "Error: the database directory (/var/lib/ldap) is empty but not the config directory (/etc/ldap/slapd.d)"
     exit 1
     exit 1
+
+  #
+  # Error: the config directory (/etc/ldap/slapd.d) is empty but not the database directory (/var/lib/ldap)
+  #
   elif [ ! -z "$(ls -A /var/lib/ldap)" ] && [ -z "$(ls -A /etc/ldap/slapd.d)" ]; then
   elif [ ! -z "$(ls -A /var/lib/ldap)" ] && [ -z "$(ls -A /etc/ldap/slapd.d)" ]; then
-    echo "the config directory (/etc/ldap/slapd.d) is empty but not the database directory (/var/lib/ldap)"
+    log-helper error "Error: the config directory (/etc/ldap/slapd.d) is empty but not the database directory (/var/lib/ldap)"
     exit 1
     exit 1
 
 
+  #
+  # An existing database and config are provided
+  #
   else
   else
-    # there is an existing database and config
-
     # if the config was bootstraped with TLS
     # if the config was bootstraped with TLS
     # to avoid error (#6) we check tls files
     # to avoid error (#6) we check tls files
     if [ -e "$WAS_STARTED_WITH_TLS" ]; then
     if [ -e "$WAS_STARTED_WITH_TLS" ]; then
-
-      . $WAS_STARTED_WITH_TLS
-
+      source $WAS_STARTED_WITH_TLS
       check_tls_files $PREVIOUS_LDAP_TLS_CA_CRT_PATH $PREVIOUS_LDAP_TLS_CRT_PATH $PREVIOUS_LDAP_TLS_KEY_PATH $PREVIOUS_LDAP_TLS_DH_PARAM_PATH
       check_tls_files $PREVIOUS_LDAP_TLS_CA_CRT_PATH $PREVIOUS_LDAP_TLS_CRT_PATH $PREVIOUS_LDAP_TLS_KEY_PATH $PREVIOUS_LDAP_TLS_DH_PARAM_PATH
     fi
     fi
   fi
   fi
 
 
+  #
   # start OpenLDAP
   # start OpenLDAP
+  #
 
 
-
-  function startOpenLDAP(){
-
-    if [ -n "$PREVIOUS_HOSTNAME" ]; then
-      PREVIOUS_HOSTNAME="ldap://$PREVIOUS_HOSTNAME"
-    fi
-
-    #start openldap normaly
-    echo -n "Starting openldap..."
-    slapd -h "ldap://$HOSTNAME $PREVIOUS_HOSTNAME ldap://localhost ldapi:///" -u openldap -g openldap
-    echo "[ok]"
-  }
-
-  # start OpenLDAP with previous replication configuration
+  # get previous hostname if OpenLDAP was started with replication
+  # to avoid configuration pbs
+  PREVIOUS_HOSTNAME_PARAM=""
   if [ -e "$WAS_STARTED_WITH_REPLICATION" ]; then
   if [ -e "$WAS_STARTED_WITH_REPLICATION" ]; then
 
 
-    . $WAS_STARTED_WITH_REPLICATION
+    source $WAS_STARTED_WITH_REPLICATION
 
 
+    # if previous hostname != current hostname
+    # set previous hostname to a loopback ip in /etc/hosts
     if [ "$PREVIOUS_HOSTNAME" != "$HOSTNAME" ]; then
     if [ "$PREVIOUS_HOSTNAME" != "$HOSTNAME" ]; then
       echo "127.0.0.2 $PREVIOUS_HOSTNAME" >> /etc/hosts
       echo "127.0.0.2 $PREVIOUS_HOSTNAME" >> /etc/hosts
-    else
-      PREVIOUS_HOSTNAME=""
+      PREVIOUS_HOSTNAME_PARAM="ldap://$PREVIOUS_HOSTNAME"
     fi
     fi
   fi
   fi
 
 
-  startOpenLDAP
+  # start OpenLDAP
+  log-helper info "Start OpenLDAP..."
+  slapd -h "ldap://$HOSTNAME $PREVIOUS_HOSTNAME_PARAM ldap://localhost ldapi:///" -u openldap -g openldap
 
 
-  # set bootstrap config part 2
+
+  #
+  # setup bootstrap config - Part 2
+  #
   if $BOOTSTRAP; then
   if $BOOTSTRAP; then
 
 
+    log-helper info "Add bootstrap schemas..."
+
     # add ppolicy schema
     # add ppolicy schema
-    ldapadd -c -Y EXTERNAL -Q -H ldapi:/// -f /etc/ldap/schema/ppolicy.ldif
+    ldapadd -c -Y EXTERNAL -Q -H ldapi:/// -f /etc/ldap/schema/ppolicy.ldif 2>&1 | log-helper debug
 
 
     # convert schemas to ldif
     # convert schemas to ldif
     SCHEMAS=""
     SCHEMAS=""
@@ -145,15 +167,14 @@ EOF
 
 
     # add schemas
     # add schemas
     for f in $(find ${SERVICE_DIR}/slapd/assets/config/bootstrap/schema -name \*.ldif -type f); do
     for f in $(find ${SERVICE_DIR}/slapd/assets/config/bootstrap/schema -name \*.ldif -type f); do
-      echo "Processing file ${f}"
+      log-helper debug "Processing file ${f}"
       # add schema if not already exists
       # add schema if not already exists
       SCHEMA=$(basename "${f}" .ldif)
       SCHEMA=$(basename "${f}" .ldif)
       ADD_SCHEMA=$(is_new_schema $SCHEMA)
       ADD_SCHEMA=$(is_new_schema $SCHEMA)
       if [ "$ADD_SCHEMA" -eq 1 ]; then
       if [ "$ADD_SCHEMA" -eq 1 ]; then
-        echo "add schema ${SCHEMA}"
-        ldapadd -c -Y EXTERNAL -Q -H ldapi:/// -f $f
+        ldapadd -c -Y EXTERNAL -Q -H ldapi:/// -f $f 2>&1 | log-helper debug
       else
       else
-        echo "schema ${f} already exists"
+        log-helper info "schema ${f} already exists"
       fi
       fi
     done
     done
 
 
@@ -166,15 +187,16 @@ EOF
     sed -i --follow-symlinks "s|{{ LDAP_BASE_DN }}|${LDAP_BASE_DN}|g" ${SERVICE_DIR}/slapd/assets/config/bootstrap/ldif/02-security.ldif
     sed -i --follow-symlinks "s|{{ LDAP_BASE_DN }}|${LDAP_BASE_DN}|g" ${SERVICE_DIR}/slapd/assets/config/bootstrap/ldif/02-security.ldif
 
 
     # process config files in bootstrap directory (do no process files in subdirectories)
     # process config files in bootstrap directory (do no process files in subdirectories)
+    log-helper info "Add bootstrap ldif..."
     for f in $(find ${SERVICE_DIR}/slapd/assets/config/bootstrap/ldif -mindepth 1 -maxdepth 1 -type f -name \*.ldif  | sort); do
     for f in $(find ${SERVICE_DIR}/slapd/assets/config/bootstrap/ldif -mindepth 1 -maxdepth 1 -type f -name \*.ldif  | sort); do
-      echo "Processing file ${f}"
-      ldapmodify -Y EXTERNAL -Q -H ldapi:/// -f $f
+      log-helper debug "Processing file ${f}"
+      ldapmodify -Y EXTERNAL -Q -H ldapi:/// -f $f 2>&1 | log-helper debug || ldapmodify -h localhost -p 389 -D cn=admin,$LDAP_BASE_DN -w $LDAP_ADMIN_PASSWORD -f $f 2>&1 | log-helper debug
     done
     done
 
 
     # read only user
     # read only user
     if [ "${LDAP_READONLY_USER,,}" == "true" ]; then
     if [ "${LDAP_READONLY_USER,,}" == "true" ]; then
 
 
-      echo "Add read only user"
+      log-helper info "Add read only user..."
 
 
       LDAP_READONLY_USER_PASSWORD_ENCRYPTED=$(slappasswd -s $LDAP_READONLY_USER_PASSWORD)
       LDAP_READONLY_USER_PASSWORD_ENCRYPTED=$(slappasswd -s $LDAP_READONLY_USER_PASSWORD)
       sed -i --follow-symlinks "s|{{ LDAP_READONLY_USER_USERNAME }}|${LDAP_READONLY_USER_USERNAME}|g" ${SERVICE_DIR}/slapd/assets/config/bootstrap/ldif/readonly-user/readonly-user.ldif
       sed -i --follow-symlinks "s|{{ LDAP_READONLY_USER_USERNAME }}|${LDAP_READONLY_USER_USERNAME}|g" ${SERVICE_DIR}/slapd/assets/config/bootstrap/ldif/readonly-user/readonly-user.ldif
@@ -184,20 +206,21 @@ EOF
       sed -i --follow-symlinks "s|{{ LDAP_READONLY_USER_USERNAME }}|${LDAP_READONLY_USER_USERNAME}|g" ${SERVICE_DIR}/slapd/assets/config/bootstrap/ldif/readonly-user/readonly-user-acl.ldif
       sed -i --follow-symlinks "s|{{ LDAP_READONLY_USER_USERNAME }}|${LDAP_READONLY_USER_USERNAME}|g" ${SERVICE_DIR}/slapd/assets/config/bootstrap/ldif/readonly-user/readonly-user-acl.ldif
       sed -i --follow-symlinks "s|{{ LDAP_BASE_DN }}|${LDAP_BASE_DN}|g" ${SERVICE_DIR}/slapd/assets/config/bootstrap/ldif/readonly-user/readonly-user-acl.ldif
       sed -i --follow-symlinks "s|{{ LDAP_BASE_DN }}|${LDAP_BASE_DN}|g" ${SERVICE_DIR}/slapd/assets/config/bootstrap/ldif/readonly-user/readonly-user-acl.ldif
 
 
-      echo "Processing file ${SERVICE_DIR}/slapd/assets/config/bootstrap/ldif/readonly-user/readonly-user.ldif"
-      ldapmodify -h localhost -p 389 -D cn=admin,$LDAP_BASE_DN -w $LDAP_ADMIN_PASSWORD -f ${SERVICE_DIR}/slapd/assets/config/bootstrap/ldif/readonly-user/readonly-user.ldif
+      log-helper debug "Processing file ${SERVICE_DIR}/slapd/assets/config/bootstrap/ldif/readonly-user/readonly-user.ldif"
+      ldapmodify -h localhost -p 389 -D cn=admin,$LDAP_BASE_DN -w $LDAP_ADMIN_PASSWORD -f ${SERVICE_DIR}/slapd/assets/config/bootstrap/ldif/readonly-user/readonly-user.ldif 2>&1 | log-helper debug
 
 
-      echo "Processing file ${SERVICE_DIR}/slapd/assets/config/bootstrap/ldif/readonly-user/readonly-user-acl.ldif"
-      ldapmodify -Y EXTERNAL -Q -H ldapi:/// -f ${SERVICE_DIR}/slapd/assets/config/bootstrap/ldif/readonly-user/readonly-user-acl.ldif
+      log-helper debug "Processing file ${SERVICE_DIR}/slapd/assets/config/bootstrap/ldif/readonly-user/readonly-user-acl.ldif"
+      ldapmodify -Y EXTERNAL -Q -H ldapi:/// -f ${SERVICE_DIR}/slapd/assets/config/bootstrap/ldif/readonly-user/readonly-user-acl.ldif 2>&1 | log-helper debug
 
 
     fi
     fi
-
   fi
   fi
 
 
-  # tls config
+  #
+  # TLS config
+  #
   if [ "${LDAP_TLS,,}" == "true" ]; then
   if [ "${LDAP_TLS,,}" == "true" ]; then
 
 
-    echo "Use TLS"
+    log-helper info "Add TLS config..."
 
 
     LDAP_TLS_CA_CRT_PATH="${SERVICE_DIR}/slapd/assets/certs/$LDAP_TLS_CA_CRT_FILENAME"
     LDAP_TLS_CA_CRT_PATH="${SERVICE_DIR}/slapd/assets/certs/$LDAP_TLS_CA_CRT_FILENAME"
     LDAP_TLS_CRT_PATH="${SERVICE_DIR}/slapd/assets/certs/$LDAP_TLS_CRT_FILENAME"
     LDAP_TLS_CRT_PATH="${SERVICE_DIR}/slapd/assets/certs/$LDAP_TLS_CRT_FILENAME"
@@ -216,7 +239,7 @@ EOF
     sed -i --follow-symlinks "s|{{ LDAP_TLS_PROTOCOL_MIN }}|${LDAP_TLS_PROTOCOL_MIN}|g" ${SERVICE_DIR}/slapd/assets/config/tls/tls-enable.ldif
     sed -i --follow-symlinks "s|{{ LDAP_TLS_PROTOCOL_MIN }}|${LDAP_TLS_PROTOCOL_MIN}|g" ${SERVICE_DIR}/slapd/assets/config/tls/tls-enable.ldif
     sed -i --follow-symlinks "s|{{ LDAP_TLS_VERIFY_CLIENT }}|${LDAP_TLS_VERIFY_CLIENT}|g" ${SERVICE_DIR}/slapd/assets/config/tls/tls-enable.ldif
     sed -i --follow-symlinks "s|{{ LDAP_TLS_VERIFY_CLIENT }}|${LDAP_TLS_VERIFY_CLIENT}|g" ${SERVICE_DIR}/slapd/assets/config/tls/tls-enable.ldif
 
 
-    ldapmodify -Y EXTERNAL -Q -H ldapi:/// -f ${SERVICE_DIR}/slapd/assets/config/tls/tls-enable.ldif
+    ldapmodify -Y EXTERNAL -Q -H ldapi:/// -f ${SERVICE_DIR}/slapd/assets/config/tls/tls-enable.ldif 2>&1 | log-helper debug
 
 
     [[ -f "$WAS_STARTED_WITH_TLS" ]] && rm -f "$WAS_STARTED_WITH_TLS"
     [[ -f "$WAS_STARTED_WITH_TLS" ]] && rm -f "$WAS_STARTED_WITH_TLS"
     touch $WAS_STARTED_WITH_TLS
     touch $WAS_STARTED_WITH_TLS
@@ -236,25 +259,26 @@ EOF
     echo "TLS_KEY ${LDAP_TLS_KEY_PATH}" >> $HOME/.ldaprc
     echo "TLS_KEY ${LDAP_TLS_KEY_PATH}" >> $HOME/.ldaprc
 
 
   else
   else
+    log-helper info "Disable TLS config..."
 
 
-    echo "Don't use TLS"
-
-    ldapmodify -c -Y EXTERNAL -Q -H ldapi:/// -f ${SERVICE_DIR}/slapd/assets/config/tls/tls-disable.ldif || true
+    ldapmodify -c -Y EXTERNAL -Q -H ldapi:/// -f ${SERVICE_DIR}/slapd/assets/config/tls/tls-disable.ldif 2>&1 | log-helper debug || true
     [[ -f "$WAS_STARTED_WITH_TLS" ]] && rm -f "$WAS_STARTED_WITH_TLS"
     [[ -f "$WAS_STARTED_WITH_TLS" ]] && rm -f "$WAS_STARTED_WITH_TLS"
-
   fi
   fi
 
 
 
 
+
+  #
+  # Replication config
+  #
+
   function disableReplication() {
   function disableReplication() {
-    echo "Try to disable replication"
-    ldapmodify -c -Y EXTERNAL -Q -H ldapi:/// -f ${SERVICE_DIR}/slapd/assets/config/replication/replication-disable.ldif || true
+    ldapmodify -c -Y EXTERNAL -Q -H ldapi:/// -f ${SERVICE_DIR}/slapd/assets/config/replication/replication-disable.ldif 2>&1 | log-helper debug || true
     [[ -f "$WAS_STARTED_WITH_REPLICATION" ]] && rm -f "$WAS_STARTED_WITH_REPLICATION"
     [[ -f "$WAS_STARTED_WITH_REPLICATION" ]] && rm -f "$WAS_STARTED_WITH_REPLICATION"
   }
   }
 
 
-  # replication config
   if [ "${LDAP_REPLICATION,,}" == "true" ]; then
   if [ "${LDAP_REPLICATION,,}" == "true" ]; then
 
 
-    echo "Use replication"
+    log-helper info "Add replication config..."
     disableReplication || true
     disableReplication || true
 
 
     i=1
     i=1
@@ -276,8 +300,7 @@ EOF
     sed -i --follow-symlinks "/{{ LDAP_REPLICATION_HOSTS_CONFIG_SYNC_REPL }}/d" ${SERVICE_DIR}/slapd/assets/config/replication/replication-enable.ldif
     sed -i --follow-symlinks "/{{ LDAP_REPLICATION_HOSTS_CONFIG_SYNC_REPL }}/d" ${SERVICE_DIR}/slapd/assets/config/replication/replication-enable.ldif
     sed -i --follow-symlinks "/{{ LDAP_REPLICATION_HOSTS_HDB_SYNC_REPL }}/d" ${SERVICE_DIR}/slapd/assets/config/replication/replication-enable.ldif
     sed -i --follow-symlinks "/{{ LDAP_REPLICATION_HOSTS_HDB_SYNC_REPL }}/d" ${SERVICE_DIR}/slapd/assets/config/replication/replication-enable.ldif
 
 
-    echo "Enable replication"
-    ldapmodify -c -Y EXTERNAL -Q -H ldapi:/// -f ${SERVICE_DIR}/slapd/assets/config/replication/replication-enable.ldif || true
+    ldapmodify -c -Y EXTERNAL -Q -H ldapi:/// -f ${SERVICE_DIR}/slapd/assets/config/replication/replication-enable.ldif 2>&1 | log-helper debug || true
 
 
     [[ -f "$WAS_STARTED_WITH_REPLICATION" ]] && rm -f "$WAS_STARTED_WITH_REPLICATION"
     [[ -f "$WAS_STARTED_WITH_REPLICATION" ]] && rm -f "$WAS_STARTED_WITH_REPLICATION"
     touch $WAS_STARTED_WITH_REPLICATION
     touch $WAS_STARTED_WITH_REPLICATION
@@ -286,22 +309,32 @@ EOF
 
 
   else
   else
 
 
-    echo "Don't use replication"
+    log-helper info "Disable replication config..."
     disableReplication || true
     disableReplication || true
 
 
   fi
   fi
 
 
+  #
   # stop OpenLDAP
   # stop OpenLDAP
+  #
+  log-helper info "Stop OpenLDAP..."
+
   SLAPD_PID=$(cat /run/slapd/slapd.pid)
   SLAPD_PID=$(cat /run/slapd/slapd.pid)
-  echo -n "Kill slapd, pid: $SLAPD_PID..."
   kill -15 $SLAPD_PID
   kill -15 $SLAPD_PID
-  # wait until slapd is terminated
-  while [ -e /proc/$SLAPD_PID ]; do sleep 0.1; done
-  echo "[ok]"
-
-  echo "First start setup is done, remove setup files"
-  rm -rf ${SERVICE_DIR}/slapd/assets/config
+  while [ -e /proc/$SLAPD_PID ]; do sleep 0.1; done # wait until slapd is terminated
+
+  #
+  # remove config files
+  #
+  if [ "${LDAP_REMOVE_CONFIG_AFTER_SETUP,,}" == "true" ]; then
+    log-helper info "Remove config files..."
+    rm -rf ${SERVICE_DIR}/slapd/assets/config
+  fi
 
 
+  #
+  # setup done :)
+  #
+  log-helper info "First start setup is done :)"
   touch $FIRST_START_SETUP_DONE
   touch $FIRST_START_SETUP_DONE
 fi
 fi
 
 

+ 4 - 0
image/service/slapd/process.sh

@@ -1,5 +1,9 @@
 #!/bin/bash -e
 #!/bin/bash -e
 
 
+# set -x (bash debug) if log level is trace
+# https://github.com/osixia/docker-light-baseimage/blob/stable/image/tool/log-helper
+log-helper level eq trace && set -x
+
 # Reduce maximum number of number of open file descriptors to 1024
 # Reduce maximum number of number of open file descriptors to 1024
 # otherwise slapd consumes two orders of magnitude more of RAM
 # otherwise slapd consumes two orders of magnitude more of RAM
 # see https://github.com/docker/docker/issues/8231
 # see https://github.com/docker/docker/issues/8231