{"id":3067,"date":"2023-10-24T18:33:21","date_gmt":"2023-10-24T17:33:21","guid":{"rendered":"https:\/\/www.cyber-cottage.co.uk\/?p=3067"},"modified":"2023-10-24T18:38:18","modified_gmt":"2023-10-24T17:38:18","slug":"ldap-for-freepbx","status":"publish","type":"post","link":"https:\/\/www.cyber-cottage.co.uk\/?p=3067","title":{"rendered":"Ldap for FreePBX"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">Install and configure OpenLDAP server in FreePBX<\/h2>\n\n\n\n<h2 class=\"wp-block-heading\">Concept<\/h2>\n\n\n\n<p>Before diving into the installation and configuration, it&#8217;s better to know some terms used in LDAP.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Attribute<\/h3>\n\n\n\n<p>An attribute is a characteristic of an object. For example, an email of an account.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Object Class<\/h3>\n\n\n\n<p>An object class defines what attributes that object can have. For example, we define an object class, InetOrgPerson, it may contain displayName and mail&nbsp;<strong>attributes<\/strong>. Depends on the definition of object class, the attributes specified can be mandatory or optional.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Distinguished Name (DN)<\/h3>\n\n\n\n<p>Distinguished Name lets us uniquely identify the object. It is similar to the file path in a reverse order. For example,&nbsp;<strong>uid=JohnDoe,OU=People,DC=abc,DC=local<\/strong>&nbsp;is a&nbsp;<strong>DN<\/strong><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Entry<\/h3>\n\n\n\n<p>An entry is just an object. You define what object class this entry belongs to &amp; each object class defines what attributes this object has. Each entry can belong to multiple object classes and need to have all mandatory attributes specified in all object classes it belongs to.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Schema<\/h3>\n\n\n\n<p>A schema contains the definitions of various attributes and object classes.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Domain Component (DC) &amp; Organizational Unit (OU)<\/h3>\n\n\n\n<p>They are containers, contains object &amp; let you manage objects in a hierarchy manner. People use them commonly.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">OpenLDAP Installation<\/h2>\n\n\n\n<p>Install OpenLDAP related packages<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo yum install openldap* -y\nsudo systemctl start slapd\nsudo systemctl enable slapd\nsudo systemctl status slapd # Check service is started &amp; enabled<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>\u25cf slapd.service - OpenLDAP Server Daemon\n   Loaded: loaded (\/usr\/lib\/systemd\/system\/slapd.service; enabled; vendor preset: disabled)\n   Active: active (running) since Tue 2023-10-17 11:20:41 BST; 1 weeks 0 days ago\n     Docs: man:slapd\n           man:slapd-config\n           man:slapd-hdb\n           man:slapd-mdb\n           file:\/\/\/usr\/share\/doc\/openldap-servers\/guide.html\n Main PID: 1922 (slapd)\n   CGroup: \/system.slice\/slapd.service\n           \u2514\u25001922 \/usr\/sbin\/slapd -u ldap -h ldapi:\/\/\/ ldap:\/\/\/\n\nOct 24 16:46:06 testsystem.myserver.co.uk slapd&#91;1922]: conn=1604 fd=22 ACCEPT from IP=192.168.1.202:45777 (IP=0.0.0.0:389)\nOct 24 16:46:06 testsystem.myserver.co.uk slapd&#91;1922]: conn=1604 op=0 BIND dn=\"\" method=128\nOct 24 16:46:06 testsystem.myserver.co.uk slapd&#91;1922]: conn=1604 op=0 RESULT tag=97 err=0 text=\nOct 24 16:46:06 testsystem.myserver.co.uk slapd&#91;1922]: conn=1604 op=1 SRCH base=\"dc=abc,dc=local\" scope=2 deref=0 filter=\"(|(cn=*)(sn=*))\"\nOct 24 16:46:06 testsystem.myserver.co.uk slapd&#91;1922]: conn=1604 op=1 SEARCH RESULT tag=101 err=0 nentries=13 text=\nOct 24 16:46:06 testsystem.myserver.co.uk slapd&#91;1922]: conn=1604 op=2 UNBIND\nOct 24 16:46:06 testsystem.myserver.co.uk slapd&#91;1922]: conn=1604 fd=22 closed\nOct 24 16:46:49 testsystem.myserver.co.uk slapd&#91;1922]: conn=1530 op=21 SRCH base=\"dc=abc,dc=local\" scope=2 deref=0 filter=\"(cn=*)\"\nOct 24 16:46:49 testsystem.myserver.co.uk slapd&#91;1922]: conn=1530 op=21 SRCH attr=givenName title wWWHomePage telephoneNumber\nOct 24 16:46:49 testsystem.myserver.co.uk slapd&#91;1922]: conn=1530 op=21 SEARCH RESULT tag=101 err=0 nentries=13 text=<\/code><\/pre>\n\n\n\n<p><a rel=\"noreferrer noopener\" href=\"https:\/\/joeho.xyz\/static\/a17c91ba9f4f8af64a8968235ddd9603\/0012b\/openldap-installation.png\" target=\"_blank\"><\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">OpenLDAP Configuration<\/h2>\n\n\n\n<p>Generate OpenLDAP password and save it<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo slappasswd<\/code><\/pre>\n\n\n\n<p><a href=\"https:\/\/joeho.xyz\/static\/f17309a4e377261e0d826ec0449305dd\/75d93\/generate-openldap-password.png\" target=\"_blank\" rel=\"noreferrer noopener\"><\/a>Then, we will use ldapmodify to update&nbsp;<strong>\/etc\/openldap\/slapd.d\/cn=config\/olcDatabase={2}hdb.ldif<\/strong>, which is our database config file<a href=\"https:\/\/joeho.xyz\/static\/b0a754ab05b58a79f02638874fc7f09e\/38070\/original-openldap-configuration.png\" target=\"_blank\" rel=\"noreferrer noopener\"><\/a>We will create a file &amp; customize and paste content below<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>vi db.ldif<\/code><\/pre>\n\n\n\n<p>Content you should paste: You should replace with your customized values<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>olcSuffix (should be replaced by your domain, e.g. example.com -&gt; dc=example,dc=com)<\/li>\n\n\n\n<li>olcRootDN (should be replaced by your domain admin name, can be any name you prefer, e.g. admin -&gt; cn=admin,dc=abc,dc=local)<\/li>\n\n\n\n<li>olcRootPW (should be the password you generate above)<\/li>\n<\/ol>\n\n\n\n<pre class=\"wp-block-code\"><code>dn: olcDatabase={2}hdb,cn=config\nchangetype: modify\nreplace: olcSuffix\nolcSuffix: dc=abc,dc=local\n\ndn: olcDatabase={2}hdb,cn=config\nchangetype: modify\nreplace: olcRootDN\nolcRootDN: cn=admin,dc=abc,dc=local\n\ndn: olcDatabase={2}hdb,cn=config\nchangetype: modify\nreplace: olcRootPW\nolcRootPW: {SSHA}xxxxx<\/code><\/pre>\n\n\n\n<p><a href=\"https:\/\/joeho.xyz\/static\/ad6e13b382699c256727a9c72f8f57c6\/a7c74\/openldap-configuration-modified.png\" target=\"_blank\" rel=\"noreferrer noopener\"><\/a>Run this command to update.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo ldapmodify -Y External -H ldapi:\/\/\/ -f db.ldif<\/code><\/pre>\n\n\n\n<p>Configuration of <\/p>\n\n\n\n<p>\/etc\/openldap\/slapd.d\/cn=config\/olcDatabase={2}hdb.ldif&nbsp; <\/p>\n\n\n\n<p>should now change to:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.\n# CRC32 9c010289\ndn: olcDatabase={2}hdb\nobjectClass: olcDatabaseConfig\nobjectClass: olcHdbConfig\nolcDatabase: {2}hdb\nolcDbDirectory: \/var\/lib\/ldap\nolcDbIndex: objectClass eq,pres\nolcDbIndex: ou,cn,mail,surname,givenname eq,pres,sub\nstructuralObjectClass: olcHdbConfig\nentryUUID: 6ceb0374-fb9c-103d-91a1-952174d1b37c\ncreatorsName: cn=config\ncreateTimestamp: 20231010093751Z\n<strong>olcSuffix: dc=abc,dc=local\nolcRootDN: cn=admin,dc=abc,dc=local\nolcRootPW:: encryped_password_here<\/strong>\nentryCSN: 20221010095035.541034Z#000000#000#000000\nmodifiersName: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth\nmodifyTimestamp: 20221010095035Z<\/code><\/pre>\n\n\n\n<p><a rel=\"noreferrer noopener\" href=\"https:\/\/joeho.xyz\/static\/c39eeb6f1ad812ab4a1b9d2b1c8728fa\/92d15\/new-openldap-configuration.png\" target=\"_blank\"><\/a><\/p>\n\n\n\n<p>Apply some&nbsp;<a href=\"https:\/\/www.openldap.org\/doc\/admin24\/schema.html#:~:text=13.1.-,Distributed%20Schema%20Files,-OpenLDAP%20Software%20is\">commonly used schema<\/a>. The 2nd &amp; 3rd schema allow us to create an object with InetOrgPerson &amp; ShadowAccount which we will use to create an user<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo ldapadd -Y EXTERNAL -H ldapi:\/\/\/ -f \/etc\/openldap\/schema\/cosine.ldif\nsudo ldapadd -Y EXTERNAL -H ldapi:\/\/\/ -f \/etc\/openldap\/schema\/nis.ldif\nsudo ldapadd -Y EXTERNAL -H ldapi:\/\/\/ -f \/etc\/openldap\/schema\/inetorgperson.ldif<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">OpenLDAP Verification<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Create objects, Organizational Unit and group<\/h3>\n\n\n\n<p>Create a file,&nbsp;<strong>entries.ldif<\/strong>, and add below content which<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>create a user, john<\/li>\n\n\n\n<li>assign john to 2 groups, john &amp; Engineering<\/li>\n<\/ol>\n\n\n\n<pre class=\"wp-block-code\"><code>dn: dc=abc,dc=local\ndc: abc\nobjectClass: top\nobjectClass: domain\n\ndn: ou=People,dc=abc,dc=local\nobjectClass: organizationalUnit\nou: People\n\ndn: ou=Groups,dc=abc,dc=local\nobjectClass: organizationalUnit\nou: Groups\n\ndn: cn=Engineering,ou=Groups,dc=abc,dc=local\ncn: Engineering\nobjectClass: posixGroup\ngidNumber: 32452\nmemberUid: John\n\ndn: uid=John,ou=People,dc=abc,dc=local\nobjectClass: inetOrgPerson\nobjectClass: posixAccount\nobjectClass: shadowAccount\nuid: John\nsn: Doe\ngivenName: John\ncn: John Doe\ndisplayName: John Ho\nuidNumber: 32452\ngidNumber: 32452\nloginShell: \/bin\/bash\nhomeDirectory: \/home\/John\nshadowMin: 0\nshadowMax: 2\nshadowWarning: 1\nuserPassword: {CRYPT}x\nshadowLastChange: 19261\ndn: cn=john,ou=Groups,dc=abc,dc=local\ncn: John\nobjectClass: posixGroup\ngidNumber: 32452\nmemberUid: John<\/code><\/pre>\n\n\n\n<p>Apply the content<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ldapadd -x -W -D \"cn=admin,dc=abc,dc=local\" -f entries.ldif<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Test querying LDAP<\/h3>\n\n\n\n<p>Query all entries<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ldapsearch -D cn=\"admin,dc=abc,dc=local\" -W -b \"dc=abc,dc=local\"<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91;root@testsystem ldapservice]# ldapsearch -D cn=\"admin,dc=abc,dc=local\" -W -b \"dc=abc,dc=local\"\nEnter LDAP Password: \n# extended LDIF\n#\n# LDAPv3\n# base &lt;dc=abc,dc=local&gt; with scope subtree\n# filter: (objectclass=*)\n# requesting: ALL\n#\n\n# abc.local\ndn: dc=abc,dc=local\ndc: abc\nobjectClass: top\nobjectClass: domain\n\n# People, abc.local\ndn: ou=People,dc=abc,dc=local\nobjectClass: organizationalUnit\nou: People\n\n# Groups, abc.local\ndn: ou=Groups,dc=abc,dc=local\nobjectClass: organizationalUnit\nou: Groups<\/code><\/pre>\n\n\n\n<p><a href=\"https:\/\/joeho.xyz\/static\/ff5a613a2cba3d3f3436e2e813f3ba72\/9f82e\/query-result.png\" target=\"_blank\" rel=\"noreferrer noopener\"><\/a><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Change account password (Optional)<\/h3>\n\n\n\n<p>The account we created above uses a password,&nbsp;<strong>{CRYPT}x<\/strong>, which we obviously don&#8217;t want it to be, so we change the password as below<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo ldappasswd -x -D cn=admin,dc=abc,dc=local -W -S uid=john,ou=People,dc=abc,dc=local<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Now we have to create a script to extract the data<\/h3>\n\n\n\n<p>The contact data we want is in the mysql database on Freepbx, This is the asterisk database and the data is across a few tables.<\/p>\n\n\n\n<p>The basic concept that we extract the info from the db and remove add or update the entries in the ldap database.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Bash Scripts<\/h3>\n\n\n\n<p>First we have a file for the variables and passwords &#8216;fldapconfig.sh&#8217;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># LDAP Server Connection Details\nLDAP_SERVER=\"ldap:\/\/server:port\"\nLDAP_BINDDN=\"cn=admin,dc=abc,dc=local\"\nLDAP_BINDPW=\"ldappassword\"\nDB_HOST=\"localhost\"\nDB_USER=\"username\"\nDB_PASSWORD=\"mysqlsecret\"\nDB_NAME=\"asterisk\"\n\n# LDAP Entry Details\nBASE_DN=\"dc=abc,dc=local\"\nBASE_OU=\"ou=People\"\n\n# Files\nrem_file=\"\/tmp\/rem.txt\"\nadd_file=\"\/tmp\/add.txt\"\nchg_file=\"\/tmp\/chg.txt\"<\/code><\/pre>\n\n\n\n<p>Now the code. I accept no responsibility for it, Its a mess but it does what it says. There is bound to be a better way but with the timescale I had i needed something quick and as such its dirty. each section is distinct so shouldnt be hard to clean up.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>The file fpbxldap.sh <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#!\/bin\/bash\n\n#Script file to add delete and modify ladp database for freeepbx contact manager \n#Copyright (C) 2023  Ian Plain Cyber-cottage.co.uk\n#\n#This program is free software; you can redistribute it and\/or\n#modify it under the terms of the GNU General Public License\n#as published by the Free Software Foundation; either version 2\n#of the License, or (at your option) any later version.\n#\n#This program is distributed in the hope that it will be useful,\n#but WITHOUT ANY WARRANTY; without even the implied warranty of\n#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\nsource fldapconfig.sh\n\n# LDAP Entry Details\n#BASE_DN=\"dc=abc,dc=local\"\n#BASE_OU=\"ou=People\"\n\n# Search for the LDAP entries ad file them\nCURRENT_TELEPHONE_NUMBER=$(ldapsearch -x -D \"$LDAP_BINDDN\" -w \"$LDAP_BINDPW\" -H \"$LDAP_SERVER\" -b \"$BASE_OU,$BASE_DN\" telephoneNumber | awk -F ',|=|: ' '\/dn:\/ {print $3}')\necho \"$CURRENT_TELEPHONE_NUMBER\" |grep -w -v  \"People\" &gt; \/tmp\/ldapdb.txt\n\n\n# Query to execute\nQUERY=\"SELECT asterisk.contactmanager_entry_numbers.number as 'telephoneNumber', asterisk.contactmanager_group_entries.displayname as 'cn', asterisk.contactmanager_group_entries.fname as 'givenName', COALESCE(NULLIF(asterisk.contactmanager_group_entries.lname, ''), '-')  AS 'sn', asterisk.contactmanager_entry_numbers.type as 'o', asterisk.contactmanager_groups.name as 'dir'\nFROM asterisk.contactmanager_entry_numbers  \nINNER JOIN asterisk.contactmanager_group_entries ON asterisk.contactmanager_entry_numbers.entryid=asterisk.contactmanager_group_entries.id  \nINNER JOIN asterisk.contactmanager_groups ON asterisk.contactmanager_groups.id=asterisk.contactmanager_group_entries.groupid \nWHERE asterisk.contactmanager_entry_numbers.number REGEXP '^&#91;0-9]*$' AND asterisk.contactmanager_group_entries.displayname REGEXP '&#91;:alpha:]'\n;\"\n\n# Output file\nOUTPUT_FILE=\"\/tmp\/fpbxdb.txt\"\n\n# Run the MySQL query and save the result to the output file\nmysql -h \"$DB_HOST\" -u \"$DB_USER\" -p\"$DB_PASSWORD\" \"$DB_NAME\" -N -e \"$QUERY\" | sed 's\/\\t\/,\/g' &gt; \"$OUTPUT_FILE\"\n\n#Split out just the names\ncat \/tmp\/fpbxdb.txt |awk -F ',' '{print $2\" - \"$5}' &gt; \/tmp\/fpxname.txt\ncat \/tmp\/fpbxdb.txt |awk -F ',' '{print $2\" - \"$5\",\"$1}' &gt; \/tmp\/fpxnumna.txt\n\n\n# Assign filenames to variables\nlistB_file=\"\/tmp\/ldapdb.txt\"\nlistA_file=\"\/tmp\/fpxname.txt\"\n\n# Check if the files exist\nif &#91; ! -f \"$listA_file\" ]; then\n    echo \"File $listA_file does not exist.\"\n    exit 1\nfi\nif &#91; ! -f \"$listB_file\" ]; then\n    echo \"File $listB_file does not exist.\"\n    exit 1\nfi\n\n#Bit of a hack here that adds an entry to empty file, as AWK doesnt like empty files.. Thsi was quick a fix\nif &#91; -s \"$listA_file\" ]; then\n  echo \"The file is not empty.\"\nelse\n  echo \"foobar\" &gt; \/tmp\/fpxname.txt\nfi\n\nif &#91; -s \"$listB_file\" ]; then\n  echo \"The file is not empty.\"\nelse\n echo \"barfoo\" &gt; \/tmp\/ldapdb.txt\nfi\n\n# Compare the two files and echo names in List A but not in List B\nawk 'NR==FNR{a&#91;$0]++; next} !a&#91;$0]' \"$listB_file\" \"$listA_file\"  &gt; \/tmp\/add.txt\nawk 'NR==FNR{a&#91;$0]++; next} !a&#91;$0]' \"$listA_file\" \"$listB_file\"  &gt; \/tmp\/rem.txt\n\n#lets delete the entries\n# Loop through each line in the input file and run the command\nwhile IFS= read -r REM_FILTER; do\n    # Run the specified command on each line\necho \"$REM_FILTER deleted from Ldap\" &gt;&gt; \/tmp\/remlog.txt\nldapdelete -x -D \"$LDAP_BINDDN\" -w \"$LDAP_BINDPW\" -H \"$LDAP_SERVER\"  \"cn=$REM_FILTER,$BASE_OU,$BASE_DN\"\ndone &lt; \"$rem_file\"\n\necho  \"Done-------\" &gt;&gt; \/tmp\/remlog.txt\n\n#delete the previous ldif files\nrm -f \/tmp\/adding.ldif\nrm -f \/tmp\/modify.ldif\n\n#lets add the entries\n# Loop through each line in the input file and run the command\nwhile IFS= read -r ADD_FILTER; do\n# Run the specified command on each line\n# echo  $ADD_FILTER |awk -F ' - ' '{print $1; print $2}'\nms_cn=\"$(echo  $ADD_FILTER |awk -F ' - ' '{print $1}')\"\nms_o=\"$(echo  $ADD_FILTER |awk -F ' - ' '{print $2}')\"\n\n# Query to execute\nQUERY=\"SELECT asterisk.contactmanager_entry_numbers.number as 'telephoneNumber',  COALESCE(NULLIF(asterisk.contactmanager_group_entries.lname, ''), '-')  AS 'sn' \nFROM asterisk.contactmanager_entry_numbers\nINNER JOIN asterisk.contactmanager_group_entries ON asterisk.contactmanager_entry_numbers.entryid=asterisk.contactmanager_group_entries.id\nINNER JOIN asterisk.contactmanager_groups ON asterisk.contactmanager_groups.id=asterisk.contactmanager_group_entries.groupid\nWHERE asterisk.contactmanager_entry_numbers.type = '$ms_o' AND asterisk.contactmanager_group_entries.displayname = '$ms_cn'\n;\"\n\n# Run the MySQL query and save the result to the output file\nms_query=$(mysql -h \"$DB_HOST\" -u \"$DB_USER\" -p\"$DB_PASSWORD\" \"$DB_NAME\" -N -e \"$QUERY\")\n\nms_telephoneNumber=$(echo $ms_query | awk '{print $1}')\nms_sn=$(echo $ms_query | awk '{print $2}')\n\necho \"dn: cn=$ms_cn - $ms_o,ou=People,dc=abc,dc=local\" &gt;&gt; \/tmp\/adding.ldif\necho \"cn: $ms_cn - $ms_o\" &gt;&gt; \/tmp\/adding.ldif\necho \"givenName: $ms_cn - $ms_o\" &gt;&gt; \/tmp\/adding.ldif\necho \"sn: $ms_sn\" &gt;&gt; \/tmp\/adding.ldif\necho \"telephonenumber: $ms_telephoneNumber\" &gt;&gt; \/tmp\/adding.ldif\necho \"objectclass: inetOrgPerson\" &gt;&gt; \/tmp\/adding.ldif\necho \"objectclass: top\" &gt;&gt; \/tmp\/adding.ldif\necho \"\"  &gt;&gt; \/tmp\/adding.ldif\necho \"cn: $ms_cn - $ms_o , $ms_telephoneNumber  added to Ldap\" &gt;&gt; \/tmp\/addlog.txt\ndone &lt; \"$add_file\"\n\n#Lets run the ldif command\nldapadd -x  -D \"$LDAP_BINDDN\" -w \"$LDAP_BINDPW\" -H \"$LDAP_SERVER\"   -f \/tmp\/adding.ldif &gt;&gt; \/tmp\/addlog.txt\n\necho  \"Done-------\" &gt;&gt; \/tmp\/addlog.txt\n\n#OK now we are going to compare freepbx and ldap entries and update as required.\n\n#lets get the current ldap names and numbers \nldapsearch -x -D \"cn=admin,dc=abc,dc=local\" -w \"r1v3rp1g5\" -b \"ou=People,dc=abc,dc=local\"  | awk -v OFS=',' '{split($0,a,\": \")} \/^cn:\/{cn=a&#91;2]} \/^telephoneNumber:\/{telephoneNumber=a&#91;2]; print cn,telephoneNumber}' &gt; \/tmp\/ldapcsv.txt\n\nawk 'NR==FNR{a&#91;$0]++; next} !a&#91;$0]' \/tmp\/ldapcsv.txt   \/tmp\/fpxnumna.txt &gt; \/tmp\/chg.txt\nchg_file=\"\/tmp\/chg.txt\"\n\n# Loop through each line in the input file and run the command\nwhile IFS= read -r CHG_FILTER; do\n# Run the specified command on each line\n# echo  $CHG_FILTER |awk -F ',' '{print $1; print $2}'\nms_cn=\"$(echo  $CHG_FILTER |awk -F ',' '{print $1}')\"\nms_telephoneNumber=\"$(echo  $CHG_FILTER |awk -F ',' '{print $2}')\"\n\necho \"Changing telephoneNumber to $ms_telephoneNumber\"\necho \"dn: cn=$ms_cn,$BASE_OU,$BASE_DN\" &gt;&gt; \/tmp\/modify.ldif\necho \"changetype: modify\" &gt;&gt; \/tmp\/modify.ldif\necho \"replace: telephoneNumber\" &gt;&gt; \/tmp\/modify.ldif\necho \"telephoneNumber: $ms_telephoneNumber\" &gt;&gt; \/tmp\/modify.ldif\necho \"\"  &gt;&gt; \/tmp\/modify.ldif\n\necho \"$CHG_FILTER  changed in Ldap\" &gt;&gt; \/tmp\/chglog.txt\ndone &lt; \"$chg_file\"\n\nldapmodify -x -D \"$LDAP_BINDDN\" -w \"$LDAP_BINDPW\" -H \"$LDAP_SERVER\" -f \/tmp\/modify.ldif  &gt;&gt; \/tmp\/modify.ldif\n\necho  \"Done-------\" &gt;&gt; \/tmp\/chglog.txt\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Example phone configurations for Sangoma S series and Gigaset.<\/h3>\n\n\n\n<p>Gigaset example<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"580\" height=\"794\" data-attachment-id=\"3074\" data-permalink=\"https:\/\/www.cyber-cottage.co.uk\/?attachment_id=3074\" data-orig-file=\"https:\/\/i0.wp.com\/www.cyber-cottage.co.uk\/wp-content\/uploads\/2023\/10\/Screenshot-2023-10-24-at-18.23.48.png?fit=644%2C882&amp;ssl=1\" data-orig-size=\"644,882\" data-comments-opened=\"0\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"Screenshot-2023-10-24-at-18.23.48\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/www.cyber-cottage.co.uk\/wp-content\/uploads\/2023\/10\/Screenshot-2023-10-24-at-18.23.48.png?fit=580%2C794&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/www.cyber-cottage.co.uk\/wp-content\/uploads\/2023\/10\/Screenshot-2023-10-24-at-18.23.48.png?resize=580%2C794&#038;ssl=1\" alt=\"\" class=\"wp-image-3074\"\/><\/figure>\n\n\n\n<p>Sangoma S Series example<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"580\" height=\"561\" data-attachment-id=\"3075\" data-permalink=\"https:\/\/www.cyber-cottage.co.uk\/?attachment_id=3075\" data-orig-file=\"https:\/\/i0.wp.com\/www.cyber-cottage.co.uk\/wp-content\/uploads\/2023\/10\/image-1.png?fit=670%2C648&amp;ssl=1\" data-orig-size=\"670,648\" data-comments-opened=\"0\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"image-1\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/www.cyber-cottage.co.uk\/wp-content\/uploads\/2023\/10\/image-1.png?fit=580%2C561&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/www.cyber-cottage.co.uk\/wp-content\/uploads\/2023\/10\/image-1.png?resize=580%2C561&#038;ssl=1\" alt=\"\" class=\"wp-image-3075\"\/><\/figure>\n\n\n\n<p>Im sure this will work with other systems that support Ldap directories<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Install and configure OpenLDAP server in FreePBX for handset directories<\/p>\n","protected":false},"author":1,"featured_media":3004,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"content-type":"","advanced_seo_description":"","jetpack_seo_html_title":"","jetpack_seo_noindex":false,"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[2,11],"tags":[23,244,40,242,51,243,73,100,76],"class_list":["post-3067","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog","category-knowledge","tag-asterisk","tag-directories","tag-freepbx","tag-ldap","tag-linux","tag-openldap","tag-support","tag-technical","tag-voip"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/www.cyber-cottage.co.uk\/wp-content\/uploads\/2023\/03\/icon_linux_big.png?fit=40%2C40&ssl=1","jetpack_shortlink":"https:\/\/wp.me\/p5daZy-Nt","jetpack_sharing_enabled":true,"jetpack_likes_enabled":false,"jetpack-related-posts":[],"_links":{"self":[{"href":"https:\/\/www.cyber-cottage.co.uk\/index.php?rest_route=\/wp\/v2\/posts\/3067","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.cyber-cottage.co.uk\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.cyber-cottage.co.uk\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.cyber-cottage.co.uk\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.cyber-cottage.co.uk\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3067"}],"version-history":[{"count":10,"href":"https:\/\/www.cyber-cottage.co.uk\/index.php?rest_route=\/wp\/v2\/posts\/3067\/revisions"}],"predecessor-version":[{"id":3081,"href":"https:\/\/www.cyber-cottage.co.uk\/index.php?rest_route=\/wp\/v2\/posts\/3067\/revisions\/3081"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.cyber-cottage.co.uk\/index.php?rest_route=\/wp\/v2\/media\/3004"}],"wp:attachment":[{"href":"https:\/\/www.cyber-cottage.co.uk\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3067"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.cyber-cottage.co.uk\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3067"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.cyber-cottage.co.uk\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3067"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}