Using LDAP Paged Controls with Python

Most LDAP servers can be set to return an unlimited number of entries on an LDAP search, however depending on the size of the LDAP database/directory this can possibly exceed your memory. Moreover if you want to write portable code, you probably should not depend on the LDAP server being able to return unlimited entries. For instance, AD’s LDAP generally defaults to 1,000 entries maximum.

Because using LDAP paging isn’t very difficult there’s not a lot of reason to not use it. Adding paging only marginally reduces performance, while certainly putting less stress on the LDAP server(s). Personally I recommend you use it on a general basis, even where not strictly necessary.

Python’s LDAP supports paging, though it isn’t well documented. I found two examples this one and this one. Both had their pluses, but neither explained what was going on too much. I melded them together, added comments, and streamlined a bit. Hopefully this will help you get the mojo…

As a final note, one of the documents I found said the paged controls did not work with OpenLDAP. That’s not what I found – pretty much the exact code above worked without issue with OpenLDAP.


A GitHub “Gist” for the above can be found here.


For users of Python LDAP 2.4, you should check out of the comment by Ilya Rumyantsev which gives a forward/backward compatible set of code snippets since the API has changed a bit. Many thanks to Ilya for the update.


Below I took Ilya’s updates and merged them in with some minor enhancements to compare the Python LDAP version on the fly. My next stop is to take this and convert it to a generator function, which would be more ideal than using a callback. The issue with going to a generator is handling the errors, which means throwing exceptions in some sane fashion…


It turns out that the Python “ldap” module does not follow “StrictVersion” versioning in it’s “__version__” string. I have updated the “UPDATE 3” code to use “LooseVersion” comparisons.


I updated the above code to default to “criticality=False” for the paging control. If the LDAP service doesn’t support paging, it will yield a potentially confusing “Critical extension is unavailable” error.

Note I need to ultimately fix the exception handling as for whatever reason the exception object passed back doesn’t have a reasonable “__str__()” method and the message is left in the “desc” key.

How to probe ethernet capabilities…

Mostly for my own edification – use “ethtool”, eg:

You’ll note two important details about this output:

  1. This NIC is gig capable but is only running at 100mbs.
  2. I claim to be running this as root, but any good sysad should be using “sudo” instead!

Anyway, simple command, but sometimes you forget them.

Mmmm… Mmmm…

A little off topic but, when in Philadelphia… Mmmm… Mmmm…

Internation Smokeless BBQ Restaurant and Buffet



Mmmmm… Mmmmm… again!

E MEI Restaurant

Nothing new here…

But everyone should read it:

Password strength. Longer better than complexity.

How to dump the Firefox history (Linux)

Not pretty, but gets you there:

  • Find and go to your Firefox profile (usually you can locate by going to “~/.mozilla/firefox/*.default”).
  • Run “sqlite3 places.sqlite .dump | grep moz_places”

If Firefox is running you may have to copy the “places.sqlite” to a new file then run the “sqlite3” against it. You can’t dump it while Firefox is running because it locks the database.

Since it’s SQL there are fancier ways of pulling the actual tables, but for a quick script, this will do.

Note if you’re after the time that a URL was accessed (I was), it seems to be the last field in the “VALUES”. It is is in microseconds since 1970. In that case, this little Perl snippet should get you the actual time:

where “HISTORYTIME” is replaced by the time printed in the SQL dump (eg: a big arse number like “1373383738987790”).

Out of the mouths of Astronauts…

Applies to IT as well:

“And it’s worth remembering, too, there’s no problem so bad that you can’t make it worse also.”

– Commander Chris Hadfield, Canadian Astronaut

Testing “sendmail” with immediate delivery

In the old days when using “sendmail” if you wanted to watch the SMTP conversation between the local host and the next mail relay all you’d have to do is either run “sendmail -v” or “mail -v” (or “mailx -v” depending on the OS). It would then output the entire SMTP conversation with the remote host, which is useful for diagnosing why a remote host may be refusing your mail.

In more modern implementations “sendmail” actually uses two separate configurations, a “” which is used for originating mail, and “” which is used for delivery/forwarding. Subsequently when you use “sendmail -v” without any additional options it uses “” by default, which actually delivers to “localhost” first. Eg:

The solution is to add the “-Am” flag which tells it to bypass the “” and use “” directly:

Note depending on your OS you may have to run “sendmail” with “sudo” to get enough permissions to access the queue entries. You also ideally should provide the “-t” options and put things in like “To:”, “From:”, and “Subject:” to be a good mail citizen, though for testing it isn’t terribly important.

Make Excel text fit row height

As part of my job I for better or worse have to deal with Excel on a regular basis. One of the issues I have is the sizing of rows (the cell height) not properly expanding, or conversely shrinking, when I add or remove data in the cell.

It turns out there is a very easy way to clean the row height spacing:

First, select the rows you want to fix the spacing on. For most spreadsheets without fancy formatting, the simplest bet seems to be to select all cells by clicking the left corner of all the cells (examples here are from Excel 2013):

Then assure you are on the home tab:

Then select “Format / AutoFit Row Height”:

Voila! Sane cell height spacing again.

This is particularly useful with “Wrap text” set in cell “Alignment”. Note with wrapping you may have to expand the size of some columns to get Excel not to think there needs to be extra height underneath with text that is very close to the right edge of the cell.

And now for something completely different…

My big sister who I am eminently proud of:

Bragging done for today.

Dear Secure Companies…

Dear Secure Companies,

Please stop sending me emails to pick up critical documents or surveys where the URLs I need to follow point into random unverifiable domains. A link that leads to a URL like:

is not going to inspire confidence and, assuming it isn’t spear-fishing or malware, is teaching end users bad practice. That is, it’s teaching end users to follow random links rather than verifiable domains. Encouraging recipients to follow such links is completely askew to modern security awareness training which is to tell the users not to follow random links.

I know that using 3rd party marketing, survey, and even content providers is the norm, but you need to make the effort to ensure the URLs fall under your own verifiable domain, not some random 3rd party domain. Otherwise, unfortunately, you are part of the problem.

I say this because in my day job I regularly get emails from major security companies or entities handling PII that embed links in their email going to what appear to be random (though undoubtedly valid) sites. This is bad practice and you are not helping the overall picture when doing so.