Sébastien Wains

A blog about Linux, Open Source, VoIP and other geeky stuff.

Feb 25, 2015

Tested with Active Directory 2003 and RHEL 7.0

For RHEL 6.0 see here

I consider that the server is correctly set up, its hostname should be set accordingly to the Active Directory domain. It should also be synchronised with NTP. A clock drift could cause issues because of Kerberos.

I assume an AD domain "EXAMPLE" (long name: intranet.example.org)

# host -t srv _kerberos._tcp.intranet.example.org
_kerberos._tcp.intranet.example.org has SRV record 0 100 88 srv00a.intranet.example.org.
_kerberos._tcp.intranet.example.org has SRV record 0 100 88 srv00c.intranet.example.org.
_kerberos._tcp.intranet.example.org has SRV record 0 100 88 srv00b.intranet.example.org.

Install the packages:

# yum -y install authconfig samba samba-winbind samba-winbind-clients pam_krb5 krb5-workstation oddjob-mkhomedir nscd adcli ntp

Enable the services at boot:

# systemctl start smb
# systemctl enable smb
# systemctl start winbind
# systemctl enable winbind
# systemctl start oddjobd 
# systemctl enable oddjobd
# systemctl start dbus

Edit /etc/krb5.conf:

[logging]
 default = FILE:/var/log/krb5libs.log
 kdc = FILE:/var/log/krb5kdc.log
 admin_server = FILE:/var/log/kadmind.log

[libdefaults]
 default_realm = INTRANET.EXAMPLE.ORG
 dns_lookup_realm = true
 dns_lookup_kdc = true
 ticket_lifetime = 24h
 renew_lifetime = 7d
 forwardable = true

[realms]
 EXAMPLE.COM = {
  kdc = kerberos.example.com
  admin_server = kerberos.example.com
 }

 INTRANET.EXAMPLE.ORG = {
 }

[domain_realm]
 .example.com = EXAMPLE.COM
 example.com = EXAMPLE.COM
 intranet.example.org = INTRANET.EXAMPLE.ORG
 .intranet.example.org = INTRANET.EXAMPLE.ORG

Test Kerberos:

# kinit username@INTRANET.EXAMPLE.ORG
# klist

username should be domain admin in the Active Directory.

klist should gives this kind of output:

Ticket cache: FILE:/tmp/krb5cc_0
Default principal: username@INTRANET.EXAMPLE.ORG

Valid starting       Expires              Service principal
02/25/2015 15:23:30  02/26/2015 01:23:30  krbtgt/INTRANET.EXAMPLE.ORG@INTRANET.EXAMPLE.ORG
    renew until 03/04/2015 15:23:28

Delete the Kerberos ticket you just initialized:

# kdestroy

Edit /etc/samba/smb.conf:

[global]
workgroup = EXAMPLE
realm = INTRANET.EXAMPLE.ORG
security = ads
idmap uid = 10000-19999
idmap gid = 10000-19999
idmap config EXAMPLE:backend = rid
idmap config EXAMPLE:range = 10000000-19999999
;winbind enum users = no
;winbind enum groups = no
;winbind separator = +
winbind use default domain = yes
winbind offline logon = false
template homedir = /home/EXAMPLE/%U
template shell = /bin/bash

    server string = Samba Server Version %v

    log file = /var/log/samba/log.%m
    log level = 10
    max log size = 50
    passdb backend = tdbsam

[share]
    path = /home/share
    comment = Some cool directory
    writable = yes
    browseable = yes
    # there's a trust between EXAMPLE and EXAMPLE2
    valid users = username EXAMPLE2\username
    directory mask = 0777
    create mask = 0777

Restart Samba:

# systemctl restart smb

Join the domain:

# net join -S EXAMPLE -U username

It should work and you can then get information regarding the join:

# net ads info
LDAP server: 192.168.0.1
LDAP server name: SRV00C.intranet.example.org
Realm: INTRANET.EXAMPLE.ORG
Bind Path: dc=INTRANET,dc=EXAMPLE,dc=ORG
LDAP port: 389
Server time: Wed, 25 Feb 2015 15:27:05 CET
KDC server: 192.168.0.1
Server time offset: 0

Create the directory for AD users:

# mkdir /home/EXAMPLE/
# chmod 0777 /home/EXAMPLE/

Restart Winbind:

# systemctl restart winbind

Sources:

redhat.com

Feb 17, 2015

I just migrated this blog from Wordpress to Scriptogr.am.

Mainly because this blog isn't so much active anymore, those SQL IOPS were useless for something that had become so static (I disabled the comments many years ago, tired of spam).

I missed Posterous and started looking for something similar, until I found about Calepin.co and Scriptogr.am.

For those of you who don't know, Scriptogr.am will fetch markdown text files from your Dropbox and turn them into a website.

What I like about this approach is that all my articles are stored locally (in a readable format) on my computer, and I can grep, sed and awk the hell out of them.

On the Mac, I use Mou and on Android Draft. I still have to find a good editor on Linux.

Draft can connect to your Dropbox and synchronise with any folder, so you can pick your posts folder. Most similar apps don't give you a choice.

Mou has many interesting features and has integrated with Scriptogram, so you can push your articles straight from the editor.

The downside of Scriptogr.am is probably the lack of comments (which I don't care about, and some people came up with the code to have Disqus anyway), the inability to search inside your blog (you have to Google it), and the fact that if you need several blogs on the platform, you have to have as many Dropbox accounts. I can deal with that, I have a personal and work Dropbox account, I both use them for this blog and my travel blog.

I used exitwp to convert the XML export of Wordpress into markdown.

Now, you might actually start seeing new content now all over again, given how easy it is to publish stuff :-)

Feb 16, 2015

I use Terminator as my terminal app, and use the "watch for activity" feature a lot. With the following command, I'd get notified as soon as the connection is opened.

while ! nc -vz localhost 3306; do sleep 1; done
echo 'Database is available'
Feb 16, 2015

This command will allow you to pipe trafic generated by tcpdump on a remote machine into Wireshark running on your local machine:

ssh root@dest tcpdump -U -s0 -w - 'tcp port 389' | wireshark -k -i -
Feb 16, 2015

This has been tested on DCS-930L and DCS-5020L

<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
<data version="1.25.0">
  <trigger type="wifi_connected">
    <useDefaultName>true</useDefaultName>
    <name>WiFi Connected: SSID</name>
    <enabled>true</enabled>
    <all>false</all>
    <ssidList>SSID</ssidList>
  </trigger>
  <trigger type="wifi_disconnected">
    <useDefaultName>true</useDefaultName>
    <name>WiFi Disconnected: SSID</name>
    <enabled>true</enabled>
    <all>false</all>
    <ssidList>SSID</ssidList>
  </trigger>
  <condition type="active_network_type">
    <useDefaultName>true</useDefaultName>
    <name>Active Network Type: Mobile</name>
    <none>false</none>
    <mobile>true</mobile>
    <wifi>false</wifi>
    <wimax>false</wimax>
    <bluetooth>false</bluetooth>
    <ethernet>false</ethernet>
  </condition>
  <action type="http_request">
    <useDefaultName>true</useDefaultName>
    <name>HTTP Request: POST https://webcam.public.url/setSystemMotion application/x-www-form-urlencoded ReplySuccessPage=motion.htm,ReplyErrorPage=motion.htm,MotionDetectionEnable=0,MotionDetectionScheduleDay=30,ConfigSystemMotion=Save store in motion</name>
    <url>https://webcam.public.url/setSystemMotion</url>
    <verifyCertificates>true</verifyCertificates>
    <basicAuthentication>true</basicAuthentication>
    <username>admin</username>
    <httpMethod>POST</httpMethod>
    <httpContentType>X_WWW_FORM_URLENCODED</httpContentType>
    <contentType>text/plain</contentType>
    <generalTextData></generalTextData>
    <formFieldList>ReplySuccessPage=motion.htm,ReplyErrorPage=motion.htm,MotionDetectionEnable=0,MotionDetectionScheduleDay=30,ConfigSystemMotion=Save</formFieldList>
    <timeout>60000</timeout>
    <storeInVariable>true</storeInVariable>
    <variable>motion</variable>
    <path>/storage/emulated/0/Download/file.bin</path>
  </action>
  <action type="http_request">
    <useDefaultName>true</useDefaultName>
    <name>HTTP Request: POST https://webcam.public.url/setSystemMotion application/x-www-form-urlencoded ReplySuccessPage=motion.htm,ReplyErrorPage=motion.htm,MotionDetectionEnable=1,MotionDetectionScheduleDay=30,MotionDetectionScheduleMode=0,MotionDetectionSensitivity=50,ConfigSystemMotion=Save store in response</name>
    <url>https://webcam.public.url/setSystemMotion</url>
    <verifyCertificates>true</verifyCertificates>
    <basicAuthentication>true</basicAuthentication>
    <username>admin</username>
    <httpMethod>POST</httpMethod>
    <httpContentType>X_WWW_FORM_URLENCODED</httpContentType>
    <contentType>text/plain</contentType>
    <generalTextData></generalTextData>
    <formFieldList>ReplySuccessPage=motion.htm,ReplyErrorPage=motion.htm,MotionDetectionEnable=1,MotionDetectionScheduleDay=30,MotionDetectionScheduleMode=0,MotionDetectionSensitivity=50,ConfigSystemMotion=Save</formFieldList>
    <timeout>60000</timeout>
    <storeInVariable>true</storeInVariable>
    <variable>response</variable>
    <path>/storage/emulated/0/Download/file.bin</path>
  </action>
  <action type="notification_status_bar">
    <useDefaultName>true</useDefaultName>
    <name>Notification on Statusbar: Webcam disabled House ID 2</name>
    <notificationIcon>HOUSE</notificationIcon>
    <title>Webcam disabled</title>
    <message>Motion disabled</message>
    <sound>false</sound>
    <vibrate>false</vibrate>
    <flashLED>false</flashLED>
    <flashLEDColor>#ff00ff00</flashLEDColor>
    <flashLEDOn>500</flashLEDOn>
    <flashLEDOff>500</flashLEDOff>
    <flagLocalOnly>false</flagLocalOnly>
    <flagOngoing>false</flagOngoing>
    <flagNoClear>false</flagNoClear>
    <notificationIDEnabled>true</notificationIDEnabled>
    <notificationID>2</notificationID>
    <priority>DEFAULT</priority>
    <visibility>PRIVATE</visibility>
    <messageBigEnabled>false</messageBigEnabled>
    <messageBig></messageBig>
    <largeIconEnabled>false</largeIconEnabled>
    <largeIcon></largeIcon>
  </action>
  <action type="notification_status_bar">
    <useDefaultName>true</useDefaultName>
    <name>Notification on Statusbar: Webcam enabled House ID 3</name>
    <notificationIcon>HOUSE</notificationIcon>
    <title>Webcam enabled</title>
    <message>Motion enabled</message>
    <sound>false</sound>
    <vibrate>false</vibrate>
    <flashLED>false</flashLED>
    <flashLEDColor>#ff00ff00</flashLEDColor>
    <flashLEDOn>500</flashLEDOn>
    <flashLEDOff>500</flashLEDOff>
    <flagLocalOnly>false</flagLocalOnly>
    <flagOngoing>false</flagOngoing>
    <flagNoClear>false</flagNoClear>
    <notificationIDEnabled>true</notificationIDEnabled>
    <notificationID>3</notificationID>
    <priority>DEFAULT</priority>
    <visibility>PRIVATE</visibility>
    <messageBigEnabled>false</messageBigEnabled>
    <messageBig></messageBig>
    <largeIconEnabled>false</largeIconEnabled>
    <largeIcon></largeIcon>
  </action>
  <action type="remove_notification_status_bar">
    <useDefaultName>true</useDefaultName>
    <name>Remove Notification on Statusbar: 2 (Automagic)</name>
    <automagicNotifications>true</automagicNotifications>
    <all>false</all>
    <notificationID>2</notificationID>
    <overall>true</overall>
    <packageName></packageName>
    <allOfApp>true</allOfApp>
    <filterNotificationID></filterNotificationID>
  </action>
  <action type="remove_notification_status_bar">
    <useDefaultName>true</useDefaultName>
    <name>Remove Notification on Statusbar: 3 (Automagic)</name>
    <automagicNotifications>true</automagicNotifications>
    <all>false</all>
    <notificationID>3</notificationID>
    <overall>true</overall>
    <packageName></packageName>
    <allOfApp>true</allOfApp>
    <filterNotificationID></filterNotificationID>
  </action>
  <action type="sleep">
    <useDefaultName>true</useDefaultName>
    <name>Sleep: 15s (allow device sleep)</name>
    <duration>15s</duration>
    <keepDeviceAwake>false</keepDeviceAwake>
  </action>
  <flow type="flow">
    <name>Webcam disable motion</name>
    <group>Webcam</group>
    <enabled>true</enabled>
    <lastExecutionStartTime>1417460412281</lastExecutionStartTime>
    <lastExecutionEndTime>1417460413698</lastExecutionEndTime>
    <executionPolicy>PARALLEL</executionPolicy>
    <triggercontainer id="t1" x="-70.0" y="87.5">
      <trigger>WiFi Connected: SSID</trigger>
    </triggercontainer>
    <actioncontainer id="t2" x="-70.0" y="262.5">HTTP Request: POST https://webcam.public.url/setSystemMotion application/x-www-form-urlencoded ReplySuccessPage=motion.htm,ReplyErrorPage=motion.htm,MotionDetectionEnable=0,MotionDetectionScheduleDay=30,ConfigSystemMotion=Save store in motion</actioncontainer>
    <actioncontainer id="t3" x="280.0" y="787.5">Remove Notification on Statusbar: 3 (Automagic)</actioncontainer>
    <actioncontainer id="t4" x="35.0" y="577.5">Notification on Statusbar: Webcam disabled House ID 2</actioncontainer>
    <connection from="t1" to="t2" type="NORMAL" sourcePosition="SOUTH" targetPosition="NORTH" />
    <connection from="t2" to="t4" type="NORMAL" sourcePosition="SOUTH" targetPosition="NORTH" />
    <connection from="t4" to="t3" type="NORMAL" sourcePosition="SOUTH" targetPosition="NORTH" />
  </flow>
  <flow type="flow">
    <name>Webcam enable motion</name>
    <group>Webcam</group>
    <enabled>true</enabled>
    <lastExecutionStartTime>1417459379523</lastExecutionStartTime>
    <lastExecutionEndTime>1417459399056</lastExecutionEndTime>
    <executionPolicy>PARALLEL</executionPolicy>
    <triggercontainer id="t1" x="-175.0" y="17.5">
      <trigger>WiFi Disconnected: SSID</trigger>
    </triggercontainer>
    <actioncontainer id="t2" x="-175.0" y="227.5">Sleep: 15s (allow device sleep)</actioncontainer>
    <conditioncontainer id="t3" x="-175.0" y="472.5">Active Network Type: Mobile</conditioncontainer>
    <actioncontainer id="t4" x="-175.0" y="682.5">HTTP Request: POST https://webcam.public.url/setSystemMotion application/x-www-form-urlencoded ReplySuccessPage=motion.htm,ReplyErrorPage=motion.htm,MotionDetectionEnable=1,MotionDetectionScheduleDay=30,MotionDetectionScheduleMode=0,MotionDetectionSensitivity=50,ConfigSystemMotion=Save store in response</actioncontainer>
    <actioncontainer id="t5" x="105.0" y="262.5">Notification on Statusbar: Webcam enabled House ID 3</actioncontainer>
    <actioncontainer id="t6" x="105.0" y="682.5">Remove Notification on Statusbar: 2 (Automagic)</actioncontainer>
    <connection from="t1" to="t2" type="NORMAL" sourcePosition="SOUTH" targetPosition="NORTH" />
    <connection from="t2" to="t3" type="NORMAL" sourcePosition="SOUTH" targetPosition="NORTH" />
    <connection from="t3" to="t4" type="TRUE" sourcePosition="SOUTH" targetPosition="NORTH" />
    <connection from="t3" to="t2" type="FALSE" sourcePosition="SOUTH" targetPosition="NORTH" />
    <connection from="t4" to="t5" type="NORMAL" sourcePosition="SOUTH" targetPosition="NORTH" />
    <connection from="t5" to="t6" type="NORMAL" sourcePosition="SOUTH" targetPosition="NORTH" />
  </flow>
</data>
Oct 10, 2014

In legacy versions of rsyslog, if you want to use the option PreserveFQDN, you have to set the option before anything else, or it wouldn't work.

If you are having issues sending logs from nxlog on Windows to rsyslog legacy, you might want to have a look at EscapeControlCharactersOnReceive.

http://www.rsyslog.com/doc/rsconf1_escapecontrolcharactersonreceive.html

Sep 10, 2014

This PHP page allows to retrieve configuration items to populate Rundeck inventory:

<?php

// iTop CMDB inventory for Rundeck.
// Virtual servers have VIRT tag, physicals get PHYS tag.

$host = "127.0.0.1";
$db = "itop_srv";
$user = "root";
$pwd = "";

$connect = mysql_connect($host, $user, $pwd);
mysql_select_db($db);

$query_physical = "SELECT 
        view_Server.id AS id,
        view_Server.name AS hostname,
        view_Server.description AS description,
        view_Server.osfamily_name AS osName,
        view_Server.osversion_name AS osVersion,
        view_Server.location_name AS location,
        view_Server.business_criticity AS criticity,
        view_Server.status AS status,
        view_ApplicationSolution.name AS role 
FROM 
        view_Server
LEFT JOIN 
        lnkapplicationsolutiontofunctionalci 
ON 
        lnkapplicationsolutiontofunctionalci.functionalci_id = view_Server.id 
LEFT JOIN 
        view_ApplicationSolution 
ON
        lnkapplicationsolutiontofunctionalci.applicationsolution_id = view_ApplicationSolution.id
ORDER BY
        view_Server.name;
;";

$query_virtual = "SELECT 
        view_VirtualMachine.id AS id,
        view_VirtualMachine.name AS hostname,
        view_VirtualMachine.description AS description,
        view_VirtualMachine.osfamily_name AS osName,
        view_VirtualMachine.osversion_name AS osVersion,
        view_VirtualMachine.virtualhost_name AS location,
        view_VirtualMachine.business_criticity AS criticity,
        view_VirtualMachine.status AS status,
        view_ApplicationSolution.name AS role 
FROM 
        view_VirtualMachine
LEFT JOIN 
        lnkapplicationsolutiontofunctionalci 
ON 
        lnkapplicationsolutiontofunctionalci.functionalci_id = view_VirtualMachine.id 
LEFT JOIN 
        view_ApplicationSolution 
ON
        lnkapplicationsolutiontofunctionalci.applicationsolution_id = view_ApplicationSolution.id
ORDER BY
        view_VirtualMachine.name;
;";

$result_physical = mysql_query($query_physical, $connect);
$result_virtual = mysql_query($query_virtual, $connect);

// output
header('Content-type: text/xml');

echo "<project>\n";
echo "<!-- PHYSICAL -->\n";

// returns physicals
while($row = mysql_fetch_object($result_physical))
{
        $arch=explode(" ",$row->osVersion);
        if ($row->status == "production") {
                $status = "ON";
        } elseif ($row->status == "obsolete") {
                $status = "OFF";
        } else {
                $status = "STATUS_UNKNOWN";
        }

        echo "    <node name=\"$row->hostname\" type=\"node\"\n";
        echo "        description=\"" . utf8_encode($row->description) . "\"\n";
        echo "        hostname=\"$row->hostname\"\n";
        echo "        username=\"root\"\n";
        echo "        osFamily=\"$row->osName\"\n";
        echo "        osName=\"$arch[0]\"\n";
        echo "        osVersion=\"$arch[1]\"\n";
        echo "        osArch=\"$arch[2]\"\n";
        echo "        tags=\"$status,PHYS,$arch[0],$arch[1],$arch[2],$row->criticity,ROOM_$row->location,$row->role\"\n";
        echo "        file-copy-destination-dir=\"/var/tmp/\"\n";
        echo "    />\n";
}

echo "<!-- VIRTUAL -->\n";

// returns virtuals
while($row = mysql_fetch_object($result_virtual))
{
        $arch=explode(" ",$row->osVersion);
        if ($row->status == "production") {
                $status = "ON";
        } elseif ($row->status == "obsolete") {
                $status = "OFF";
        } else {
                $status = "STATUS_UNKNOWN";
        }

        echo "    <node name=\"$row->hostname\" type=\"node\"\n";
        echo "        description=\"" . utf8_encode($row->description) . "\"\n";
        echo "        hostname=\"$row->hostname\"\n";
        echo "        username=\"root\"\n";
        echo "        osFamily=\"$row->osName\"\n";
        echo "        osName=\"$arch[0]\"\n";
        echo "        osVersion=\"$arch[1]\"\n";
        echo "        osArch=\"$arch[2]\"\n";
        echo "        tags=\"$status,VIRT,$arch[0],$arch[1],$arch[2],$row->criticity,ROOM_$row->location,$row->role\"\n";
        echo "        file-copy-destination-dir=\"/var/tmp/\"\n";
        echo "    />\n";
}

echo "</project>\n";
?>
Dec 25, 2013

By default, if you pipe commands, the exit status reported will be the one of the last command.

Example:

ls -l test.txt | mail -s "test" example@example.org

If test.txt doesn't exist, the exit status would still be 0 because the mail command was successful.

If you want to change that behavior, you should enable the pipefail builtin:

> false
> echo $?
1
> true
> echo $?
0
> false | true
> echo $?
0
> set -o pipefail
> false | true
> echo $?
1
Nov 14, 2013

I recently had to set up an outbound Postfix server with SASL authentication against LDAP.

I'm a huge fan of Dovecot, so I did go with it instead of Cyrus which was a pain to set up a few years back. Not sure about now.

I hadn't done that in a while, and if you look up on this site, you'll see I actually did SASL auth against MySQL, a couple of years ago. Since then, Dovecot reached v2, which involves a lot of changes in the configuration files.

Tested on RHEL 6.3 + Postfix 2.6.6 + Dovecot 2.0.9 + Thunderbird 17 and Outlook 2003/7/10

I assume you install Postfix and Dovecot with yum from the RHEL repositories.

Just add the configuration in the configuration files and you should be fine. Tune to your liking. Some settings may not be the most sensible for your environment, so please do not blindly copy-paste and be done with it.

/etc/postfix/master.conf

# SASL Auth
mynetworks = 127.0.0.0/8
smtpd_sasl_auth_enable = yes
broken_sasl_auth_clients = yes
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_security_options = noanonymous
smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination

# Display the auth user in the headers
smtpd_sasl_authenticated_header = yes

# Next hop
relayhost=[smtp.example.org]:25

# Postfix TLS
smtpd_tls_auth_only = no
smtp_use_tls = no
smtpd_use_tls = no
smtp_tls_note_starttls_offer = no
smtpd_tls_cert_file = /etc/ssl/certs/mycert.pem
smtpd_tls_key_file = /etc/ssl/certs/mycert.pem
smtpd_tls_loglevel = 1
smtpd_tls_received_header = yes
smtpd_tls_session_cache_database = btree:/var/lib/postfix/smtpd_tls_session_cache
smtpd_tls_session_cache_timeout = 3600s
tls_random_source = dev:/dev/urandom

/etc/postfix/master.conf

smtps    inet    n    -    n    -    10    smtpd
    -o smtpd_sasl_auth_enable=yes
        -o smtpd_tls_wrappermode=yes
        -o smtpd_client_connection_count_limit=5
        -o smtpd_client_connection_rate_limit=5

/etc/dovecot/dovecot.conf

auth_mechanisms = plain login
disable_plaintext_auth = no

# I'm only using Dovecot for SASL auth, not POP or IMAP
protocols = none

ssl = no

# Debug
auth_debug=no
auth_verbose=no
auth_debug_passwords=no
mail_debug=yes
verbose_ssl=no
auth_verbose_passwords=no

# Postfix SASL auth
service auth {
  unix_listener /var/spool/postfix/private/auth {
    group = postfix
    mode = 0660
    user = postfix
  }
  user = root
}

passdb {
  driver = ldap
  args = /etc/dovecot/ldap.conf.ext
}

I owe you a bit of explanation here though.

I'm using the auth_bind method. It means you check if the user is valid by making a bind with the provided credentials. This is nice, you don't need to have access to the password string in LDAP (which I didn't have), and deal with the hashing method used.

Also, something specific to my environment: users would configure their client with their username, which in ldap is under "companyLoginName". Somehow, Dovecot needs to test against the CN, so you have to lookup the companyLoginName string in order to retrieve the cn, you can do so with pass_filter. Then you assign the resulting CN as the actual username (see: pass_attrs).

/etc/dovecot/ldap.conf.ext

hosts = ldap.example.org
dn = cn=some,ou=string,ou=from,o=ldap
dnpass = password

debug_level = 0

auth_bind = yes
base = ou=somewhere,o=ldap
scope = subtree

pass_attrs = cn=user
pass_filter = (&(objectClass=companyAccount)(companyLoginName=%u))
Nov 14, 2013

I can never seem to remember the correct command

inotifywait -e modify -m -r /home/dir