Cleaning this up, it was an email . . .
This is going to contain some notes, scripts, and howto's on installing and administering openldap.
I have copious notes and information on this, I will be filling it in as time permits.
The problem with openldap is the examples tend not to use cn=admin,cn=config as the base, and it's confusing
...... something something-else foo="Someth ing Else", wow wassup Which is fine but you also get weird unseen whitespace that bites you in the a**: ...... word1 word2 word3<a space char> word4 word5 it just so happens there is a SPACE after word3 and it works, if you remove the space you get: ...... word1 word2 word3word4 word5, bitch blows up with a cryptic error When I manually create I never leave spaces at the end, and double them at the beginning of the continuation line <code> word word word word word = "word word word word word word"
Lastly queries can return things you do not put in a modify/add like “StructuralObjectClass: …” i.e. Any items that are implied from the DN or system generated like modify timestamps can get returned but not added/updated with a tool. Basically there are two kinds of objects… Objects that identify something, and objects that can contain other objects. That would be a 'StructuralObject', dc=, o=, ou=, or even cn= but not uid= and it's all downhill from there… Most tools will help you.
All the syntax is just abjectly arcane.
I have a huge update for this thing. Will update this page as time permits.
What follows is my “replicate” script. Mis-named really, but it sets up openldap for a server pair, primary then secondary. It has an example of pretty much everything, but basically lets you install or reinstall slapd with sane defaults for permissions. Durring install just hit enter on the defaults, it will wipe it out with the info from the definitions at the top of the file. You can use it to create a single instance.
<rant>
I generally use o=Master as a base, and for a level2 item I will add a password which grants permission to the rest of the tree above… So for example:
dc=ksmith.com,o=Master dc=cfns.net,o=Master dc=casafiesta.org,o=Master
Represent the bases for a few of the domains in my tree. Each of these dn's has a password that allows blanket r/w access up the tree for that domain. Then I like to create a read-only dn:
cn=lookup,dc=ksmith.com,o=Master
goes up the tree (it can't read passwords, except it's own).
“Standards” would have one creating (3) Three databases with bases dc=com dc=net and dc=org, and build up from there. Or you could use a bottom: o=bottom (master) and build them up:
dc=ksmith,dc=com,o=Master uid=keith,ou=People,dc=ksmith,dc=com,o=Master
As long as you are only 2 dc's deep it's not too bad. but now I have to deal with
dc=iwojimashipmates,dc=cfns,dc=net,o=Master
which is a seperate entity along with
dc=admin,dc=cfns,dc=net,o=Master
Now just type along with me, and untangle your fingers. And the rules start getting wierd to propogate up the tree so for me it's:
dc=admin.cfns.net,o=Master dc=iwojimashipmates.cfns.net,o=Master
It's just a hack, but the defaults build these crazy ldap trees, which are a bitch to type, when it's all arbitrary anyway. I mean a tree with a “base” like
dc=mymachine,dc=mydomain,dc=com
Is fine. But I'm not ever going to expand my directory from dc=com out, or even dc=mydomain.. And the content is arbitrary, so you could set your base to:
dc=mymachine.mydomain.com
So my base dn now doesn't have a bunch of “dc=”'s and commas to trip up my fingers, or use o= or, . . . I don't run ”.com“ so I don't need a huge tree above
</rant>
Have FUN!
There are a zillion artifacts in this stupid thing… I have a cleaned up update I will get in place here as time permits but the reference material is sound.
./replicate –master -p MYLLDAPPASSWORD
#!/bin/sh # # Script: replicate # Title: Create replicated LDAP servers # # Last Modified: 2020-04-02 10:08:34 # dbtype=mdb rootpass=MYLDAPPASSWORD #mirror1=prd-auth-1a #mirror2=prd-auth-1b #mirror1=qa-auth-01 #mirror2=qa-auth-02 mirror1=dev-auth-01 mirror2=dev-auth-02 BASE_DN="o=Master" ROOT_DN="cn=Admin,$BASE_DN" MANAGE_DN="cn=admin,cn=config" #os=centos7 #os=debian9 os=ubuntu18 case "$os" in centos*) ldap_user=ldap ldap_group=ldap etcdir=/etc/openldap libdir=/usr/lib64/openldap vardir=/var/lib/ldap slapd_default=/etc/default/slapd dbnum=2 ;; debian*|ubuntu*) ldap_user=openldap ldap_group=openldap etcdir=/etc/ldap libdir=/usr/lib/ldap vardir=/var/lib/ldap slapd_default=/etc/default/slapd dbnum=1 ;; esac slapdir=$etcdir/slapd.d cfgdir="$slapdir/cn=config" #---------------------------------------------------------------------- # ADD_CONFIG_MIRROR # Add Mirroring to Config #---------------------------------------------------------------------- add_config_mirror() { pause "--- Remove syncprov, Ignore Errors" # Kill it if it's there. $ldmod <<EOF_ADD_CONFIG_MIRROR1 dn: olcOverlay=syncprov,olcDatabase={0}config,cn=config changetype: delete EOF_ADD_CONFIG_MIRROR1 echo "--- End of error ignore" # Now Fixup the mirror pause "--- Fixup Mirror\n" $ldmod <<EOF_ADD_CONFIG_MIRROR2 dn: cn=config changetype: modify replace: olcServerID olcServerID: 1 ldap://${mirror1} olcServerID: 2 ldap://${mirror2} dn: olcDatabase={0}config,cn=config changetype: modify replace: olcSyncRepl olcSyncRepl: rid=001 provider=ldap://${mirror1} binddn="cn=admin,cn=config" bindmethod=simple credentials=${rootpass} searchbase="cn=config" type=refreshAndPersist retry="5 6 30 +" timeout=1 olcSyncRepl: rid=002 provider=ldap://${mirror2} binddn="cn=admin,cn=config" bindmethod=simple credentials=${rootpass} searchbase="cn=config" type=refreshAndPersist retry="5 6 30 +" timeout=1 - replace: olcMirrorMode olcMirrorMode: TRUE dn: olcOverlay=syncprov,olcDatabase={0}config,cn=config changetype: add objectClass: olcOverlayConfig objectClass: olcSyncProvConfig olcOverlay: syncprov EOF_ADD_CONFIG_MIRROR2 [ $? -ne 0 ] && echo "Mirror fix failure" } #---------------------------------------------------------------------- # ADD_CONFIG_PASSWORD # Add olcRootDN/olcRootPW and olcAccess to the cn=config database #---------------------------------------------------------------------- add_config_password() { pause "--- Update cn=config database password/permissions" # First Update the config database $ldmod <<UPDATE_CONFIG_PASSWORD dn: olcDatabase={0}config,cn=config changetype: modify replace: olcRootDN olcRootDN: $MANAGE_DN - replace: olcRootPW olcRootPW: $root_pw - replace: olcAccess olcAccess: to * by dn="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" write by dn="cn=admin,cn=config" write UPDATE_CONFIG_PASSWORD # --- } #---------------------------------------------------------------------- # ADD_CONFIG_SYNC_MODULE # Add Replication modules to cn=config #---------------------------------------------------------------------- add_config_sync_module() { pause "--- Add Sync Module" $ldmod <<ADD_CONFIG_SYNC_MODULE dn: cn=module,cn=config changetype: add objectClass: olcModuleList cn: module olcModulePath: $libdir olcModuleLoad: syncprov ADD_CONFIG_SYNC_MODULE } #---------------------------------------------------------------------- # ADD_DATABASE # Add a database to the config tree # Use the same password as for cn=admin,cn=config #---------------------------------------------------------------------- add_database() { pause "--- Add Database ($dbnum/$dbtype)" ldifpass="`slappasswd -h '{SSHA}' -s $rootpass`" ldapadd -v -Y EXTERNAL -H ldapi:/// <<ADD_DATABASE_EOF dn: olcDatabase={$dbnum}${dbtype},cn=config objectClass: olcDatabaseConfig objectClass: olc${dbtype}Config olcDatabase: {$dbnum}${dbtype} olcDbDirectory: /var/lib/ldap olcSuffix: $BASE_DN olcLastMod: TRUE olcLimits: {0}dn.exact="" time.soft=unlimited time.hard=unlimited size.soft=unlimited size.hard=unlimited olcRootDN: cn=admin,$BASE_DN olcRootPW: $ldifpass olcDbIndex: uid pres,eq olcDbIndex: cn,sn,mail,givenname pres,eq,approx,sub olcDbIndex: objectClass eq,pres olcDbIndex: uidNumber eq olcDbIndex: gidNumber eq olcDbIndex: EntryUUID eq olcDbIndex: ou eq olcDbIndex: uniqueMember eq olcDbIndex: memberUid eq olcDbMaxSize: 107374182400 olcAccess: to dn.regex="(.+,)?(dc=[^,]+,$BASE_DN)\$" attrs=userPassword,shadowLastChange by dn="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" write by dn.exact,expand="\$2" write by anonymous auth by dn="cn=admin,$BASE_DN" write by dn="cn=admin,cn=config" write by * none olcAccess: to attrs=userPassword,shadowLastChange by dn="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" write by self write by anonymous auth by dn="cn=admin,$BASE_DN" write by dn="cn=admin,cn=config" write by * none olcAccess: to dn.regex=".*cn=([^,]+),ou=Personal,(dc=[^,]+,$BASE_DN)\$" by dn="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" write by dn.exact,expand="uid=\$1,ou=People,\$2" write by dn.exact,expand="\$2" write by dn="cn=admin,$BASE_DN" write by dn="cn=admin,cn=config" write olcAccess: to dn.regex="(.+,)?(dc=[^,]+,$BASE_DN)$" by dn="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" write by self write by dn="cn=admin,$BASE_DN" write by dn="cn=admin,cn=config" write by dn.exact,expand="\$2" write by dn.subtree,expand="\$2" read by dn.exact,expand="cn=lookup,\$2" read by dn="cn=lookup,$BASE_DN" read olcAccess: to * by self write by dn="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" write by dn="cn=admin,$BASE_DN" write by dn="cn=admin,cn=config" write by dn="cn=lookup,$BASE_DN" read ADD_DATABASE_EOF cat - > /dev/null <<ADD_DATABASE_EOF2 ADD_DATABASE_EOF2 } #---------------------------------------------------------------------- # ADD_DATABASE_BASEDN # Now add the base dn structure to it's database #---------------------------------------------------------------------- add_database_basedn() { pause "Add $BASE_DN to Database Proper" $ldmod <<EOF_ADD_BASE_DN dn: $BASE_DN changetype: add objectclass: organization objectclass: top o: Master EOF_ADD_BASE_DN } #---------------------------------------------------------------------- # ADD_DATABASE_MIRROR # Only on the Master # Add Mirroring to Backend Database Config #---------------------------------------------------------------------- add_database_mirror() { # pause "--- Updating Database ($dbnum/$dbtype): Remove olcOverlay (May Fail)" # # echo "$ldmod" # $ldmod <<EOF_ADD_DATABASE_MIRROR1 #dn: olcOverlay=syncprov,olcDatabase={$dbnum}${dbtype},cn=config #changetype: delete #EOF_ADD_DATABASE_MIRROR1 pause "--- Updating Database ($dbnum/$dbtype): Add olcSyncRepl olcOverlay, Turn on Mirror Mode" $ldmod <<EOF_ADD_DATABASE_MIRROR2 dn: olcDatabase={$dbnum}${dbtype},cn=config changetype: modify replace: olcLimits olcLimits: dn.exact="$MANAGE_DN" time.soft=unlimited time.hard=unlimited size.soft=unlimited size.hard=unlimited - replace: olcSyncRepl olcSyncRepl: rid=0${dbnum}1 provider=ldap://${mirror1} binddn="cn=admin,cn=config" bindmethod=simple credentials=${rootpass} searchbase="$BASE_DN" type=refreshAndPersist retry="5 6 30 +" timeout=1 olcSyncRepl: rid=0${dbnum}2 provider=ldap://${mirror2} binddn="cn=admin,cn=config" bindmethod=simple credentials=${rootpass} searchbase="$BASE_DN" type=refreshAndPersist retry="5 6 30 +" timeout=1 - replace: olcMirrorMode olcMirrorMode: TRUE dn: olcOverlay=syncprov,olcDatabase={$dbnum}${dbtype},cn=config changetype: add objectClass: olcOverlayConfig objectClass: olcSyncProvConfig olcOverlay: syncprov EOF_ADD_DATABASE_MIRROR2 } #---------------------------------------------------------------------- # ADD_DATABASE_PASSWORD # Add olcRootDN/olcRootPW to the directory database #---------------------------------------------------------------------- add_database_password() { pause "--- Update MDB database password/permissions" $ldmod <<UPDATE_BASE_EOF2 dn: olcDatabase={1}mdb,cn=config changetype: modify replace: olcSuffix olcSuffix: $base_dn - replace: olcRootDN olcRootDN: $root_dn - replace: olcRootPW olcRootPW: $root_pw UPDATE_BASE_EOF2 # --- } #---------------------------------------------------------------------- # ADD_SCHEMAS #---------------------------------------------------------------------- add_schemas() { pause "--- Add Schema" for schema in collective duaconf dyngroup misc openldap ppolicy java \ samba mozillaabpersonalpha evolutionperson openssh-lpk_openldap do ldif="$etcdir/schema/$schema.ldif" if [ -f "$ldif" ] then echo "--- Adding Schema: $schema" ldapadd -Y EXTERNAL -H ldapi:/// -f $ldif fi done } #---------------------------------------------------------------------- # CMD_ECHO # Echo then run a command #---------------------------------------------------------------------- cmd_echo() { echo "--- $*" eval "$*" } #---------------------------------------------------------------------- # PAUSE # Echo any arguments, wait for a carriage return if debug is on #---------------------------------------------------------------------- pause() { if [ "$debug" = "y" ] then /bin/echo -e "$* >\c" read line else echo "$*" fi } #---------------------------------------------------------------------- # CREATE_DIR # Create/Re-Create LDAP Directory Tree #---------------------------------------------------------------------- create_dir() { pause "--- Re-create $vardir" if [ "$vardir" = "" ] then echo "*** No VARDIR!, Aborting" exit 0 fi rm -rf ${vardir} mkdir ${vardir} chmod 0700 ${vardir} chown ${ldap_user}:${ldap_group} ${vardir} } #---------------------------------------------------------------------- # INSTALL_SLAPD # Purge SLAPD if installed # Install a fresh SLAPD #---------------------------------------------------------------------- install_slapd() { systemctl stop slapd case "$os" in debian*|ubuntu*) # Make sure ldap-utils is installed dpkg -l | grep ldap-utils > /dev/null 2>&1 || \ apt-get -y install ldap-utils # Purge slapd if already installed dpkg -l | grep slapd > /dev/null 2>&1 && \ apt-get -y purge slapd && rm -r ${vardir} # Install slapd & remove some stuff DEBIAN_FRONTEND=noninteractive apt-get install slapd #rm -v "${cfgdir}/cn=module{0}.ldif" #rm -v "${cfgdir}/cn=schema/cn={1}cosine.ldif" #rm -v "${cfgdir}/cn=schema/cn={2}nis.ldif" #rm -v "${cfgdir}/cn=schema/cn={3}inetorgperson.ldif" ;; centos*) pause "remove openldap-servers" yum -y remove openldap-servers [ "$slapdir" != "" ] && rm -rf $slapdir/ pause "installing openldap-servers" yum -y install openldap-servers openldap-clients ;; esac # Stop the server, clear out to only cn=config pause "--- Stopping slapd" systemctl stop slapd rm -v "${cfgdir}/olcDatabase={${dbnum}}"* create_dir # Update the default startup to fix -h ... issues # Restart the server. Should be a blank cn=config # And add a password and permissions echo "--- Starting slapd" update_host # Update host file systemctl start slapd add_config_password add_config_sync_module add_config_mirror } #---------------------------------------------------------------------- # UPDATE_HOST # In order for syncrepl to work . . . # Our hostname used in the syncrepl parms, must either reside in # /etc/hosts as the first item after our IP address or ... # Invoking slapd -h '...' one of the arguments must match the syncrepl # provider URL *EXACTLY*, or and it barfs. #---------------------------------------------------------------------- update_host() { host=`hostname -s` ip=`ip address | awk '/inet / && ! /127.0.0.1/ { print $2 ; exit }'` if grep " $host " /etc/hosts > /dev/null 2>&1 then return fi echo "$ip $host" >> /etc/hosts } #---------------------------------------------------------------------- # UPDATE_SLAPD_DEFAULT # Not used . . . See UPDATE_HOST #---------------------------------------------------------------------- update_slapd_default() { pause "--- Updating $slapd_default" cat $slapd_default | awk -v host=`hostname -s` ' /^SLAPD_SERVICES=/ { printf "SLAPD_SERVICES=\"ldapi:/// ldap://%s\"\n",host next } { print $0 } ' > $slapd_default.new if diff $slapd_default $slapd_default.new then rm $slapd_default.new else mv $slapd_default $slapd_default.old mv $slapd_default.new $slapd_default fi } #---------------------------------------------------------------------- # UPDATE_SLAVE_FOLDERS #---------------------------------------------------------------------- update_slave_folders() { pause "--- update_slave_folders" dbnum=1 while [ -f "$slapdir/cn=config/olcDatabase={$dbnum}${dbtype}.ldif" ] do eval `cat "$slapdir/cn=config/olcDatabase={$dbnum}${dbtype}.ldif" | awk ' # /olcDbDirectory:/ { printf "db_folder=\"%s\"\n",$2 } '` # `' mkdir $db_folder chown 0700 $db_folder chown ${ldap_user}:${ldap_group} $db_folder dbnum=`expr $dbnum + 1` done } #---------------------------------------------------------------------- # MAIN #---------------------------------------------------------------------- echo "LDAP Replication Script" debug=n while [ "x$1" != "x" ] do case "x$1" in x--debug) debug=y ;; x--master) function=master ;; x--slave) function=slave ;; x--password|x-p) shift rootpass="$1" ;; esac shift done if [ "$rootpass" = "" ] then echo "Root Password Not Defined" exit 1 fi # This is the LDAP Version of the password root_pw=`slappasswd -s $rootpass` # ldadd="ldapadd -v -h localhost -x -D cn=admin,cn=config -w $rootpass" ldmod="ldapmodify -v -Y EXTERNAL -H ldapi:///" case "$function" in master) install_slapd add_schemas add_database add_database_basedn add_database_mirror ;; slave) install_slapd ;; esac