What Is an LDIF File? The Text File That Lists a Directory and Its Password Hashes
LDIF files are text lists of directory entries, and they can store password hashes. Jump to your question below, or work through it in order.
What Is an LDIF File? The text format for LDAP directory entries and changes
Short answer
An LDIF file is a text file that lists the entries of an LDAP directory. Every entry is a block of name and value lines that ends at a blank line. Servers, address books and migration tools write and read LDIF files.
We loaded one LDIF file with 14 entries into a test server and then damaged it in 55 ways. Our own script printed no message on 16 copies, and 8 of those 16 loaded wrong data in at least one reader.
To open an LDIF file, go to the opening steps. To check one, go to the six steps. If an import fails, begin with the eight causes.
LDIF files are text files that list the entries of an LDAP directory. Every entry is a block of name and value lines. OpenLDAP, Active Directory tools and address books read and write LDIF files.
LDAP is a protocol for reading and changing directories of people, groups and devices. Every directory entry has attributes and a distinguished name, called the DN. LDIF writes those entries as text, so you can export them, edit them and load them into another server.
RFC 2849 defines the format. G. Good of iPlanet wrote it in June 2000, and it is a Proposed Standard. Wikipedia on LDIF adds that the format began at the University of Michigan in the early 1990s, and it lists .ldif as the LDIF file extension.
An LDIF file contains one of two things. It lists entries, which is what ldapsearch and slapcat write. Or it lists changes, which are add, modify, delete and rename requests. RFC 2849 allows one kind per file, and the kinds part shows both.
FileInfo lists one type for the .ldif ending, an LDAP Data Interchange Format file in its Data Files group. It names Thunderbird, Apple Contacts, Active Directory Explorer, Apache Directory and two LDAP browsers as programs that open it. Unlike the LDF file, the ending has no second meaning.
Where our LDIF file comes from
We wrote one LDIF file ourselves, because files from live directories contain personal data. It has 14 entries in 5,271 bytes and 200 lines. They are a base entry, an organizational unit and 12 invented people from many countries, so the LDIF file contains accents and password hashes.
We loaded it into OpenLDAP 2.6.10 on Linux with ldapadd, and all 14 entries went in. We read them back with ldapsearch, and every entry matched the LDIF file. That load is our proof that the LDIF file is valid.
Then we damaged the LDIF file in 55 ways, one change at a time. Four checks handled the 55 copies. They are the file command, ldapadd, the Python ldif module 4.3.0 and a script of our own. We list the limits in the format part.
LDIF file facts at a glance
| Property | Value |
|---|---|
| Meaning | LDAP Data Interchange Format. A text format for directory entries and for changes to them. |
| Made by |
OpenLDAP tools like ldapsearch and slapcat, the Microsoft tool ldifde and address books.
|
| Format | Text in UTF-8. Our LDIF file has 200 lines, 14 entries and 15 base64 values. |
| Start |
The line version: 1 in our LDIF file. RFC 2849 says the number must be 1 when the line is there.
|
| End of an entry | One blank line. A missing blank line joins two entries. |
| Standard | RFC 2849, June 2000, a Proposed Standard. |
| Opens with |
A text editor, ldapadd, Thunderbird and LDAP browsers. Two Windows viewers read LDIF files too.
|
| MIME type |
Wikipedia lists text/ and a plain text type. We found no registered entry in the part of the IANA list we could read.
|
| Size in our set | 5,271 bytes for the original and 1,317 to 10,544 bytes for the damaged LDIF files. |
| Our tests | One LDIF file, 55 damaged LDIF files, three readers and a script, on Linux. |
Wrong page? Look at the SQL Server LDF page for a SQL Server log, the MDB file for an Access database or the DAT file for unknown data.
What Is Inside an LDIF File? One entry, line by line, from the version to the blank line
Our LDIF file has 14 entries on 200 lines. Every entry starts with a dn line and lists its attributes as names and values. A blank line ends it. Long values fold onto a second line that starts with one space.
The figure shows one entry from our LDIF file, shortened. The numbers on it match the parts below. Read the entry from the top, because the order of the lines matters.
The version line
Our LDIF file starts with version: 1. RFC 2849 on the version line says the number must be 1 and the line comes first. If it is missing, a reader can take the LDIF file for the older University of Michigan format. OpenLDAP loaded 14 entries from our copy without the line.
The dn line
Every entry starts with dn: and a distinguished name, like uid=ali. Read it from the right. The right end names the base of the tree, and the left end names the entry itself.
Attribute lines
Every other line pairs a name with a value, split by the colon and the space. Our LDIF file has 156 of them. 53 are objectClass lines, because an entry lists its classes one per line. The same name can repeat.
dn: uid=jose.muller,ou=People,dc=example,dc=com
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
cn:: Sm9zw6kgTcO8bGxlcg==
sn:: TcO8bGxlcg==
givenName:: Sm9zw6k=
uid: jose.muller
mail: jose.muller@example.com
telephoneNumber: +49 30 5550102
departmentNumber: Support
userPassword:: e1NTSEF9dG56WEtYdnZPSjU4UUpEdVNOR0xrUVdLMmtkellXeDBjMkZzZEE9P
Q==
Folded lines
A line continues on the next line if that line starts with one space. The reader removes that space and joins the two. Our LDIF file has 16 folded lines, and its longest line is 76 characters. OpenLDAP 2.6.10 wrapped its own output at 78.
RFC 2849 on folding says any non empty line can be folded and sets no maximum length. It drops the old limit of 76 characters from RFC 2045. So 76 and 78 are habits of the tools and not rules of the format.
Base64 values
Two colons mean the value is base64. Values need it if they start with a space, a colon or <. They also need it for bytes beyond ASCII. Our entry for José Müller shows both signs. His cn line decodes to his name, and his password line decodes to a hash.
The blank line
One blank line ends an entry, and extra blank lines do no harm. The line must be empty, though. A line with one space is a fold. It joined two entries in copy 21. Lines that start with # are comments.
We read this layout from one LDIF file and the RFC. The numbers come from our LDIF file. The rules come from RFC 2849 and from the OpenLDAP manual page for LDIF. Files from other tools can differ, and we tested none.
Which Kinds of LDIF File Exist? Entry files and change files, and the line that separates them
LDIF files come in two kinds. Entry files list what a directory contains. Change files list what to do to it, with changetype lines for add, modify, delete and rename. RFC 2849 allows one kind per file and not both.
The figure puts the kinds side by side. We loaded one LDIF file of both kinds into OpenLDAP. The first line after the dn shows which kind you have.
Entry files
This is the kind our study covers. ldapsearch -LLL wrote an entry file for us, and so did slapcat. The slapcat file had 298 lines for the same 14 entries, because OpenLDAP added seven lines to every entry, for example entryUUID and createTimestamp. Neither tool wrote a version line.
Change files
A change record starts with dn: and then changetype: with add, delete, modify or modrdn. Modify records list operations and separate them with lines that contain one hyphen. RFC 2849 on change records spells out all four.
We wrote a change file with two records. One replaced a phone number and added a description, and the other deleted an entry. ldapmodify applied both, and ldapsearch showed the result. Without the -a flag, ldapmodify refused our entry file and said the modify operation type was missing.
The OpenLDAP manual page says ldapadd is a hard link to ldapmodify with the add flag switched on. So use ldapadd for entry files and ldapmodify for change files.
ldapsearch, slapcat and address book exports.
changetype line.
changetype lines mark change files.
Not sure the LDIF file is an LDIF file at all? Check it with our script.
What Does One LDIF File Contain? 14 entries, 200 lines and 15 base64 values that hide nothing
Our LDIF file has 14 entries on 200 lines, and 15 of its values are base64. Base64 hides nothing, because one line of Python decodes it. The password lines decode to hashes that start with the marker {SSHA}.
We loaded the LDIF file into OpenLDAP and compared every entry we read back with the LDIF file. The figure shows where the 200 lines go and what the base64 values contain. It describes one small LDIF file that we made, and not all LDIF files.
Where the 200 lines go
Attribute lines make up 156 of the 200. Then come 16 folded lines, 14 dn lines, 13 blank lines and the version line. Two entries give the tree its shape, the base entry and the People unit. The other 12 entries describe people, and a person has 12 or 13 attribute lines.
Four people have a description, and its second line is 71 characters long. That is the longest fold. The other 12 folds are the short line Q==, which is the end of a password hash that did not fit on one line.
What base64 hides
The cn line of José Müller reads Sm9zw6kgTcO8bGxlcg==. One call to base64.b64decode in Python decodes it to his name. The accents are the reason it needs base64, because they fall outside ASCII.
The other 12 base64 values are password hashes, one per person. Every one decodes to text that starts with {SSHA}, which names a salted hash scheme. We made the hashes up for this test.
What the server added
We exported the same 14 entries with slapcat, and the LDIF file grew to 298 lines. OpenLDAP added seven lines to every entry. They give the creator, the creation time, a unique ID and a change sequence number. The values we read back with ldapsearch matched the LDIF file byte for byte.
{SSHA}.
Read the study with care. It shows one small LDIF file that we made for OpenLDAP 2.6.10. Exports from Active Directory, Thunderbird and other servers look different. We tested none of them.
What Happens When an LDIF File Is Damaged? 55 broken copies and 7 that fooled both readers
We damaged one LDIF file in 55 ways and loaded every copy with two readers. Our script printed no message on 16 copies, and 8 of those loaded wrong data in at least one reader. On 7 copies both readers loaded wrong data and said nothing.
We changed one thing at a time and sorted the 55 copies into seven groups. They cover encoding, folding, records, base64 values, cuts, names and random bytes. Copy numbers match the rows of the figure.
Green means the reader loaded the same 14 entries as the original and printed nothing. Blue is the same entries with a message. Amber is other entries with no message, and red is other entries with a message. The file column shows what the file command said.
The file command sees almost nothing
The file command printed ASCII text for 46 of the 55 copies. That includes copies with a missing dn line, wrong names and cuts inside entries. It gave the intact LDIF file the same answer. It is no check of an LDIF file.
It did spot the byte order mark, the two UTF-16 files, the Latin-1 file and the CR and CRLF line endings. Those are facts about the encoding. It printed data for the copy with a NUL byte.
Two readers, two sets of rules
Both readers loaded the original entries and printed nothing on only 9 copies. ldapadd from OpenLDAP 2.6.10 matched all 14 entries on 14 copies, and the Python module did so on 13. They disagree on 7 copies, because parsers and servers check different things.
The Python module only parses. It cannot see that an entry exists twice (copy 26) or that a parent comes later (copy 27). It also misses version 2 (copy 44) and repeated values (copy 48). ldapadd flagged all four.
The reverse happens too. ldapadd accepted the CRLF on every other line (copy 2), the byte order mark (copy 4) and DN in capitals (copy 49). The Python module refused all three.
Both readers miss the same damage
On 7 copies both readers loaded wrong data and printed nothing. They are copies 11, 28, 31, 32, 34, 36 and 41. The damage is one NUL byte, one cut password, one changed letter, single colons, a leading colon, one cut at 25 percent and three missing lines.
Copy 36 shows how quiet a cut can be. ldapadd loaded 5 entries and printed nothing, and the Python module was silent too. The fifth entry stops at uid: mei, so it has no mail, no phone and no password. Nine entries are gone.
Copy 32 changed :: to : on every value. ldapadd loaded all 14 entries and stored the password of Ali Khan as base64 text and not as the hash. Base64 has no checksum. Copy 31 changed one letter and copy 28 lost four characters of a hash, and both loaded.
A message does not mean everything failed
ldapadd matched 13 of the 14 original entries on 18 copies and printed a message on most of them. We used its -c flag. The manual page for the continue flag says the flag continues after an error and that the default is to exit after the first one. Without the flag the counts would be lower.
Copies 13 to 16 show the other side. Every person entry has a bad fold, so ldapadd matched only the 2 entries without one. The message named line 27, and it did not say that 12 entries were lost.
Our script sees syntax and misses values
Our script printed a message on 39 copies and stayed silent on 16. On 8 of the 16, both readers agreed with the original, so the silence was right. Those are copies 1, 7, 10, 17, 22, 23, 33 and 45. Copy 12 was a false alarm, because it has no final line break and still loads.
On the other 8 the script missed damage that a reader showed. They are copies 28, 31, 32, 41, 42, 48, 49 and 51. Copies 28, 31, 32 and 41 changed values, which no syntax check can see. Copies 42, 48 and 49 need a schema. A script that reads text has none.
What the groups show
| Group | What we found |
|---|---|
| A. Encoding (1 to 12) | CRLF endings, tabs after colons, a raw UTF-8 name and a missing final line break loaded cleanly. CR only and UTF-16 failed in both readers. Copy 11, with one NUL byte, loaded wrong data in both readers with no message. |
| B. Folding (13 to 18) |
On copies 13 to 16, ldapadd matched only 2 entries. Copy 15 used tabs. The OpenLDAP manual page allows them, but ldapadd 2.6.10 refused them. Copy 17 joined the folds with nothing and loaded fine.
|
| C. Records (19 to 27) |
Extra blank lines and comments did no harm. Copies 20 and 24, with a blank line inside an entry and a deleted dn line, loaded 13 entries in ldapadd with no message. Only ldapadd saw copies 26 and 27.
|
| D. Base64 and values (28 to 35) |
Copies 28, 31, 32 and 34 loaded wrong data in both readers with no message. ldapadd flagged copies 29, 30 and 35. Copy 33, with names that start with a space, was harmless.
|
| E. Cut short (36 to 41) | Cuts at 50, 75 and 90 percent drew messages. The cut at 25 percent drew none. Copy 40 ended after a dn line, and the Python module loaded it silently. Copy 41 lost three lines, and both readers were silent. |
| F. Names and header (42 to 49) |
Changing the version number still loaded all 14 entries, with a message. A missing version line was harmless. Misspelled names and missing objectClass lines drew messages from ldapadd only.
|
| G. Random bytes (50 to 55) |
ldapadd printed a message for all six copies. The Python module stayed silent on copies 51 to 54, and our script missed copy 51.
|
Read the grid with care. Green cells mean only that a reader loaded the same entries as the original. We loaded no copy into a second server or into Active Directory, and those can check more or less. Every test changed one thing in one file.
What Does Our Expert Say About LDIF Files? A note from Neeraj Singh on checking the file before an import
Check an LDIF file before you import it, and treat it like the directory itself. It lists names, mail addresses and password hashes in text that any editor opens. Our damaged LDIF files show that a bad file can load wrong data with no message.
Expert insight
An LDIF file looks harmless because any editor opens it. In our test base64 hid nothing. Damaged copies loaded with wrong data and no message. Check every LDIF file before you import it, and keep the original.
Why a readable file is the risky one
People trust a file they can read. An LDIF file looks fine in an editor, so nobody checks it before the import. Our damaged LDIF files looked fine too, and 22 of the 55 loaded wrong data in at least one reader without a message.
The readable text works the other way as well. Hashes in an LDIF file are as easy to copy as names. Share an LDIF file only with people you would trust with the directory.
Keep the original. Copy the LDIF file before you edit or import it, and write down its SHA256 hash. The hash shows which file you received and whether a later copy differs.
How Do You Open an LDIF File? An editor, a server, an address book or a viewer
Open an LDIF file in any text editor, because it is text. Load it into a server with ldapadd or ldapmodify, and read its contacts in Thunderbird or a viewer. Save it as UTF-8 when you edit it, because both of our readers refused UTF-16.
LDIF files are text, so an editor opens them. We tested ldapadd and the Python module on Linux. We read the pages of the tools below and installed none of them.
In a text editor
Any editor works. Watch three settings before you save. The encoding should be UTF-8, the byte order mark should be off and a blank line should be empty. In our copies a blank line with one space joined two entries (copy 21), and trailing spaces made ldapadd read no entry (copy 9).
One trap lives outside the editor. Microsoft says that Windows PowerShell 5.1 writes UTF-16LE when you redirect output with >. Both of our readers refused UTF-16 files (copies 5 and 6), so save the output as UTF-8.
In a directory server
Use ldapadd for entry files and ldapmodify for change files. The manual page for ldapadd says ldapadd is ldapmodify with the add flag on. Add -c to continue after an error, and read every message.
ldapadd -x -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -c -f directory.ldif
ldapmodify -x -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -f changes.ldif
ldapsearch -x -H ldap://localhost -b "dc=example,dc=com" -LLL "(objectClass=*)" > export.ldif
slapcat -l backup.ldif
ldapsearch -LLL writes entries as LDIF and leaves out the comments. slapcat reads the database files on the server itself and adds seven lines to every entry. Both wrote entry files without a version line in our test.
In address books and LDAP browsers
FileInfo on supported programs names Mozilla Thunderbird, Apple Contacts, Apple Directory Access, Active Directory Explorer, Apache Directory and two LDAP browsers as programs that open the format. Wikipedia on address books adds that Netscape Communicator and Mozilla used LDIF for address book import and export. We tested none of these.
Two Windows viewers
These cards link to two Windows programs that name LDIF files on their own pages. Both show contacts from address books. We read the pages and used neither program.
SysTools LDIF Viewer
Opens LDIF contact files on Windows
Freeviewer LDIF Viewer
Previews LDIF contacts on Windows
The SysTools page describes a free viewer for LDIF files from Mozilla and Netscape address books. It lists contacts and their attributes, sorts by nickname or email and has a find box. The page says it views any number of contacts and needs no other program.
The Freeviewer page describes a viewer for Thunderbird contacts. It shows every attribute, offers horizontal and vertical views and sorts by name, company or phone. The free version previews only, and the page lists the full version at $29. It needs .NET Framework 4.5 or later.
Neither page says how its tool treats damaged files or files from servers instead of address books. We did not use either tool on our 55 damaged LDIF files.
On the command line
Four commands show what an LDIF file is without importing it. They hash the LDIF file, print its first lines, name its encoding and start our 102 line script. The first three work on any Linux or macOS computer.
sha256sum directory.ldif
head -n 5 directory.ldif
file directory.ldif
python3 ldif_peek.py directory.ldif
The file command printed ASCII text for our intact LDIF file. That shows the encoding and nothing about the entries. The first lines show more, because version: 1 or a dn: line points to an entry file.
How the checks did on our 55 damaged LDIF files
| Check | Result |
|---|---|
| file 5.45 |
Printed ASCII text for 46 copies. It never named LDIF and never saw changed values.
|
| ldapadd 2.6.10 | Matched all 14 entries on 14 copies, with a message on 2. It matched other entries with no message on 9 copies. |
| Python ldif 4.3.0 | Matched all 14 entries on 13 copies with no message. It matched other entries with no message on 20 copies. |
| Our script | Printed a message on 39 copies and stayed silent on 16. Eight of the silent copies loaded wrong data in a reader. |
How Do You Check an LDIF File? Six steps, and a 102 line script
Check an LDIF file in six steps. Hash it, read its first lines and name its encoding. Read it with a script that checks the structure, and load it into a test server. No check proves that the values match the ones in the directory.
The six steps
- Copy the LDIF file, write down its SHA256 hash and work on the copy.
-
Read the first lines with
head -n 5 file.ldif. An entry file starts withversion: 1or adn:line.changetypelines mark change files. -
Name the encoding with
file file.ldif. You wantASCII textorUTF-8 text. Byte order marks, UTF-16 and CR line endings need fixing first. - Use the script below. It reads the structure and counts the entries.
- Read the last lines of its output. Every problem gets its own line, and the count of entries comes last.
-
Load the copy into a test server with
ldapadd -c, then compare the count and some entries with the LDIF file. Never test on the live directory.
A 102 line script that reads an LDIF file
The Python script below reads an LDIF file and does steps 3 to 5 in under a second. It checks the encoding, the line endings, the folds, every dn line, every name and value, every base64 value and the version line. It changes no file.
import re, sys, base64, binascii
NAME = re.compile(r'([A-Za-z][A-Za-z0-9;._-]*)(::|:<|:)([ \t]*)(.*)$')
def check(path):
raw = open(path, 'rb').read()
out = []
if raw[:3] == b'\xef\xbb\xbf':
out.append('byte order mark at the start')
raw = raw[3:]
if raw[:2] in (b'\xff\xfe', b'\xfe\xff') or b'\x00' in raw:
return ['UTF-16 or NUL bytes: the file is not UTF-8 text']
try:
text = raw.decode('utf-8')
except UnicodeDecodeError as e:
return ['not valid UTF-8 near byte %d' % e.start]
crlf, cr = text.count('\r\n'), text.count('\r') - text.count('\r\n')
if cr:
out.append('bare CR line endings (%d)' % cr)
if crlf and crlf != text.count('\n'):
out.append('mixed CRLF and LF line endings')
if not text.endswith('\n'):
out.append('no final line break (the file looks cut)')
lines = text.replace('\r\n', '\n').replace('\r', '\n').split('\n')
logical = []
for i, l in enumerate(lines, 1):
if l.strip() == '' and l != '':
out.append('line %d looks blank but has spaces or tabs' % i)
if l[:1] == '\t':
out.append('line %d starts with a tab, not a space' % i)
if l[:1] in (' ', '\t') and logical and logical[-1][1] != '':
logical[-1] = (logical[-1][0], logical[-1][1] + l[1:])
else:
logical.append((i, l))
recs, cur = [], []
for i, l in logical:
if l.startswith('#'):
continue
if l.strip() == '':
recs += [cur] if cur else []
cur = []
else:
cur.append((i, l))
recs += [cur] if cur else []
if recs and recs[0][0][1].lower().startswith('version:'):
if recs[0][0][1].split(':', 1)[1].strip() != '1':
out.append('version is not 1, and RFC 2849 allows only 1')
recs[0] = recs[0][1:]
recs = [r for r in recs if r]
dns = []
for rec in recs:
n, first = rec[0]
if not re.match(r'(?i)dn::?[ \t]', first):
out.append('line %d: record does not start with dn' % n)
continue
dn = first.split(':', 1)[1].lstrip(': \t').lower()
if dn in [d for _, d in dns]:
out.append('line %d: dn appears twice' % n)
dns.append((n, dn))
names = set()
for i, l in rec[1:]:
m = NAME.match(l)
if re.match(r'(?i)dn:', l):
out.append('line %d: second dn inside one record (blank line missing?)' % i)
if not m:
out.append('line %d: not "name: value"' % i)
continue
name, kind, _, val = m.groups()
names.add(name.lower())
if name.lower() == 'version':
out.append('line %d: version line is not at the start' % i)
if kind == '::':
try:
if not val.strip():
out.append('line %d: empty base64 value (%s)' % (i, name))
else:
base64.b64decode(val, validate=True)
assert len(val) % 4 == 0
except (binascii.Error, AssertionError):
out.append('line %d: base64 value is not valid (%s)' % (i, name))
elif kind == ':' and val[:1] in (':', '<'):
out.append('line %d: value starts with : or < and needs base64 (%s)' % (i, name))
elif kind == ':' and val != val.rstrip():
out.append('line %d: value ends with a space (%s)' % (i, name))
if 'objectclass' not in names:
out.append('line %d: entry has no objectClass' % n)
for k, (n, dn) in enumerate(dns):
if ',' in dn and dn.split(',', 1)[1] in [d for _, d in dns[k + 1:]]:
out.append('line %d: parent entry comes later in the file' % n)
return out + ['%d entries found' % len(recs)]
if __name__ == '__main__':
for path in sys.argv[1:]:
print(path)
groups = {}
for msg in check(path):
kind = re.sub(r' \(\w+\)$', '', re.sub(r'^line \d+:? ', '', msg))
groups.setdefault(kind, []).append(msg)
for g in groups.values():
print(' ' + g[0] + (' (and %d more like it)' % (len(g) - 1) if len(g) > 1 else ''))
On our intact LDIF file it finds 14 entries and no problem. On damaged LDIF files it names the line. It finds the missing blank line in copy 19 and the cut password in copy 38.
python3 ldif_peek.py directory.ldif
directory.ldif
14 entries found
python3 ldif_peek.py copy03.ldif
copy03.ldif
bare CR line endings (200)
no final line break (the file looks cut)
14 entries found
python3 ldif_peek.py copy14.ldif
copy14.ldif
line 28: base64 value is not valid (userPassword) (and 11 more like it)
14 entries found
python3 ldif_peek.py copy19.ldif
copy19.ldif
line 77: second dn inside one record (blank line missing?)
13 entries found
python3 ldif_peek.py copy38.ldif
copy38.ldif
no final line break (the file looks cut)
line 152: base64 value is not valid (userPassword)
11 entries found
What the script cannot see
The script reads text and not meaning. It printed nothing for copy 28, where four characters are cut off a password hash. It printed nothing for copy 31 either, where one letter changed. It also cannot know which attributes your directory allows, so it missed the misspelled name in copy 42.
python3 ldif_peek.py copy28.ldif
copy28.ldif
14 entries found
The script never executes an LDIF file. It checks that base64 values decode and does not read what they say. We wrote it from RFC 2849 and from our 55 damaged LDIF files, so it knows the faults we tested and no others.
Want the causes of an error? Go to the causes.
Is an LDIF File Safe to Share? It can store password hashes and file URLs
LDIF files are safe to open and unsafe to share. They list names, mail addresses and password hashes in text. File URLs in values make ldapadd read local files, and base64 hides nothing.
Opening an LDIF file in an editor is not the risk. The risk is what the LDIF file contains and who gets a copy. We scanned no file for malware, so we cannot say what a downloaded LDIF file contains. We can say what LDIF files can store.
What an LDIF file can contain
{SSHA} hashes. Anyone with the LDIF file has them.
:< and a file URL pull in files.
The file URL trap
RFC 2849 on file URLs lets values point to files with :< and a URL. The reader then includes the LDIF file. Its security section warns about LDIF files from untrusted sources for this reason.
We tested it. We saved a one line file in /tmp and loaded an entry whose description pointed at it. ldapadd read the LDIF file and stored its text in the description. A command like grep -n ":<" file.ldif finds such lines before you import.
Base64 is not encryption
Every base64 value in our LDIF file decoded in one line. Treat password hashes like passwords. Remove the userPassword lines before you send an LDIF file for support, and keep the original.
Before you share or import an LDIF file
- Ask who needs it. A support request rarely needs password lines.
-
Remove the
userPasswordlines and any other secret, and keep a copy of the original. - Hash the LDIF file and send the hash on another channel, so the other side can check it.
-
Search for
:<lines before you import files from strangers. - Import into a test server first, and compare the entry count with our script.
Use a copy. Work on copies of LDIF files, and write down their SHA256 hashes. Keep the original read only, so no tool can change it.
Why Does Your LDIF Import Fail? Eight causes, and what to do about every one
LDIF imports fail for eight reasons. The encoding or line endings can be wrong, folds or blank lines can be broken and base64 values can be damaged. The entries can be out of order, the server can reject an attribute or the LDIF file can be cut. The tool can also mismatch the LDIF file.
The table lists what we saw in our 55 damaged LDIF files and what the tools said. We tested OpenLDAP only. Read every fix as the first step and not as a promise.
| Cause | Details and fix |
|---|---|
| The encoding or line endings are wrong | Both of our readers refused UTF-16 (copies 5 and 6) and CR only line endings (copy 3). The Python module refused a byte order mark (copy 4). RFC 2849 on encoding says LDIF must be UTF-8. Fix: Save the LDIF file as UTF-8 with LF line endings and no byte order mark. |
| A folded line is broken |
A continued line must start with exactly one space. Copies 13 to 16 removed, doubled or replaced it. ldapadd matched only 2 entries, and the message named line 27. Fix: Put exactly one space at the start of every continued line, and join a line again if you doubt it.
|
| A blank line is missing or not empty | Missing blank lines (copy 19) made the script report a second dn inside one record. A line with one space (copy 21) became a fold. Fix: End every entry with one empty line, and keep empty lines out of the middle of an entry. |
| A base64 value is damaged |
Bad characters (copy 30) and missing padding (copy 29) drew messages. Changed letters (copy 31) and cut hashes (copy 28) drew none. Fix: Decode the value with base64 -d, compare it with the source and restore it from the original.
|
| The order of entries or the entries themselves are wrong | A child before its parent gave the error No such object (copy 27). An entry listed twice gave Already exists (copy 26). Fix: List every parent before its children, and remove the copy of an entry. |
| The server rejects an attribute |
A misspelled name gave Undefined attribute type (copy 42). A missing objectClass gave Object class violation (copy 47). A repeated value gave Type or value exists (copy 48). Fix: Check the spelling and the schema, and keep one line for every value.
|
| The file is cut short | Cuts at 50, 75 and 90 percent drew messages. A cut at 25 percent drew none and lost 9 entries (copy 36). Fix: Compare the size and the hash with the source, and export the LDIF file again. |
| The tool does not match the LDIF file |
ldapmodify refused our entry file without the -a flag. slapadd 2.6.10 refused the version: 1 line, and it loaded the same file with the line deleted. Fix: Use ldapadd for entry files and ldapmodify for change files, and delete the version line for slapadd.
|
Fix an LDIF file in seven steps
- Copy the LDIF file, write down its SHA256 hash and work on the copy.
- Read the full error message, and note the line number it names.
- Open the LDIF file at that line. Look at the dn line above it, at the folds and at the blank line before it.
-
Name the encoding with
file file.ldif. If it says UTF-16, CR or a byte order mark, save the LDIF file as UTF-8 with LF line endings. - Read the LDIF file with the check script. It names faults the importer misses.
-
Load the copy into a test server with
ldapadd -c, and compare the count of entries with the script. - If it still fails, export the LDIF file again from its source and compare the hashes.
We did not test repairs on LDIF files from other people. Files that pass our script can still fail on your server, and files that fail in the script can still load. Only your server knows what it accepts.
What to send when you ask for help
If an administrator or a forum asks about your LDIF file, send these lines. They show what was read and where it stopped, and they save rounds of questions.
Subject: LDIF import fails
File: name, size in bytes and SHA256 hash
Encoding: the output of file file.ldif
Script: the output of ldif_peek.py
Error: the full text of the message and the command that printed it
Server: the directory server and its version
History: where the LDIF file came from and what changed
Not an error, but a question about similar files? Go to the versus part.
How Do You Export, Import or Convert an LDIF File? What we tested in OpenLDAP and what the vendors say
Export LDIF files with ldapsearch, slapcat or ldifde. Import them with ldapadd, ldapmodify or ldifde. A converter reads the LDIF file and writes CSV, VCF, PDF or PST. It never changes the original. We tested the OpenLDAP tools only.
This part reports what we tested in OpenLDAP 2.6.10 and what the vendors say about the rest. We read the pages named in every paragraph and used no Windows tool.
Export from OpenLDAP
ldapsearch -LLL writes entries as LDIF without comments. slapcat reads the database files on the server and wrote 298 lines for our 14 entries, because it adds seven operational lines to every entry. Neither wrote a version line.
Import into OpenLDAP
ldapadd loads entry files and takes the version: 1 line. slapadd writes into the database files, and 2.6.10 refused our LDIF file at line 1 with the message that the attribute type version is undefined. It loaded all 14 entries after we deleted that line.
Active Directory and ldifde
Microsoft’s ldifde page describes a command line tool that creates, modifies and deletes directory objects in Active Directory. The flag -i selects import and -f names the LDIF file. The flag -m leaves out attributes that only Active Directory objects have, like objectGUID.
Wikipedia on modify records adds that ldifde needs a trailing hyphen line in modify records. We tested none of this, because we had no Active Directory.
Convert an LDIF file to another format
A converter converts the entries into rows or cards. The card below links to the one Windows converter that names LDIF files on its own page. We read the page and did not use the program.
SysTools LDIF Converter
Converts LDIF files on Windows
The SysTools page lists CSV, VCF, PDF and PST as outputs. It says the tool also reads LDF and LDAP files made by an LDAP server. It needs Windows 7 or later and .NET Framework 4.5. The page lists no file size limit, and it offers a 30 day money back refund.
The page gives two demo limits. One passage says the free version converts up to 15 items per file, and the comparison table says something else. Test the demo on your own file before you buy.
| To | Result |
|---|---|
| CSV |
A table with one row per entry. RFC 4180 defines the format. Cells take one value, so repeated attributes like objectClass need a rule.
|
| VCF | One card per person. RFC 6350 defines vCard 4.0. Address book programs import it. |
| PST | An Outlook data file. The SysTools page lists it as an output. See our PST file guide. |
| A printable list of entries. The SysTools page lists it as an output. |
How Does an LDIF File Differ From CSV, VCF and LDF Files? One directory format, two contact formats and a SQL Server log
LDIF lists directory entries with any attributes. CSV lists rows that share one set of columns. VCF stores one contact card per person. LDF only shares the name, because it is a SQL Server log.
People mix these types up because all four can list people or changes. LDIF is the one made for directories. An entry in LDIF can have any number of values for one name. The file records the tree through dn lines.
| Type | What it is |
|---|---|
| LDIF |
Text. Entries with named attributes that can repeat. The LDIF standard defines it. It can record changes through changetype lines.
|
| CSV | Text. A header row, then rows with the same columns. The CSV standard describes it. It has no tree. |
| VCF | Text. One card per person with fields for the name, phone and email. The vCard standard defines version 4.0. It was made for contacts and not for directories. |
| LDF | Binary. A SQL Server transaction log. See our guide to LDF files. |
Conversion from LDIF to CSV loses data or invents a rule, because rows have one cell per column. The reverse is easier, since every row can become an entry. Check the result against your source.
Similar endings cause other mix ups. An MDB file is a Microsoft Access database, covered in our MDB file guide. A DAT file has no fixed type, and our DAT file guide explains how to find out what it is.
What Is the LDIF File Format Made Of? The facts we could check, and where they came from
The LDIF format is text, built from entries of attribute lines that a blank line ends. The facts below come from RFC 2849, Wikipedia, FileInfo, the OpenLDAP manual pages and our checks of one LDIF file and 55 damaged LDIF files.
| Part | What we checked |
|---|---|
| Name | LDAP Data Interchange Format. Files end in .ldif. (RFC 2849, FileInfo) |
| Standard | RFC 2849 by G. Good, June 2000, a Proposed Standard. (RFC 2849, Wikipedia) |
| Origin | The University of Michigan, early 1990s. (Wikipedia) |
| Container | Text in UTF-8. Our LDIF file has 5,271 bytes and 200 lines. (RFC 2849, our LDIF file) |
| Version line |
version: 1, first in the LDIF file. The number must be 1. (RFC 2849)
|
| Entry |
The dn: line, then attribute lines, then one blank line. (RFC 2849)
|
| Value forms |
: for text, :: for base64 and :< for a URL. (RFC 2849)
|
| Folding | One space continues a line. The RFC sets no maximum line length. (RFC 2849) |
| Base64 needed |
Values that start with a space, a colon or < or have bytes beyond ASCII. (RFC 2849)
|
| Change types |
add, delete, modify and modrdn or moddn. (RFC 2849)
|
| Comments |
A line that starts with # is ignored. (RFC 2849)
|
| MIME type |
Wikipedia lists text/ and a plain text type. We found no entry in the IANA list we could read. (Wikipedia, IANA)
|
| Our counts | One LDIF file, 14 entries, 55 damaged LDIF files, three readers and a script. |
About the values we list
Rules come from RFC 2849 rules and the OpenLDAP manual page for LDIF. Counts come from our own file. FileInfo and Wikipedia are directories, so we use them for the name, the history and the programs.
The OpenLDAP manual page says a fold can start with a space or a tab, and the RFC allows only a space. In our test, ldapadd 2.6.10 refused a tab, so write one space.
What we left out
We studied one LDIF file that we wrote. It has 14 entries and one name with accents. We loaded it into OpenLDAP 2.6.10 on Linux only, and we installed no Active Directory and no Thunderbird.
We loaded no damaged copy into another server, so we cannot say how Active Directory or other servers treat them. Another server can check more than OpenLDAP does, and it can also be less strict.
We tested one change file with two records and no control lines. We read the pages of two viewers and a converter and used none of the programs. We read the IANA list only in part, and it showed no entry for LDIF.
Sources checked
For the format, see the full RFC 2849, the LDIF article on Wikipedia and the OpenLDAP manual page for LDIF. For the tools, see the ldapmodify manual page and the ldifde reference.
For encodings, see Microsoft on PowerShell character encoding. For related formats, see RFC 4180 on CSV and RFC 6350 on vCard. For the type, see the FileInfo page on LDIF files and the IANA list.
The three Windows tools are on the SysTools viewer page, the SysTools converter page and the Freeviewer page. Every count came from files and scripts in our research folder.
Frequently Asked Questions About LDIF Files
What is an LDIF file?
An LDIF file is a text file that lists the entries of an LDAP directory. Every entry starts with a dn line and lists its attributes as names and values. A blank line ends it. RFC 2849 defines the format. OpenLDAP, Active Directory tools and address books read and write LDIF files.
How do I open an LDIF file?
Open it in any text editor, because it is text. Load it into a directory with ldapadd, or read its contacts in Thunderbird or a viewer. Save it as UTF-8 when you edit it, because both of our readers refused UTF-16.
Why does my LDIF import fail?
Eight causes cover what we found. The encoding or line endings can be wrong, folds or blank lines can be broken and base64 values can be damaged. The entries can be out of order, the server can reject an attribute or the LDIF file can be cut. The tool can also mismatch the LDIF file.
How do I import an LDIF file into OpenLDAP?
Use ldapadd with the dn and password of an admin account and the file name. Add the -c flag to continue after an error. Use ldapmodify for change files. The slapadd tool 2.6.10 refused our version line, and it loaded the LDIF file after we deleted that line.
How do I convert an LDIF file to CSV?
A converter reads the LDIF file and writes a new CSV file. The SysTools page lists CSV, VCF, PDF and PST as outputs for its Windows converter. A CSV cell stores one value, so repeated attributes need a rule. Check the result against your source file.
Is an LDIF file safe to share?
No, treat it like the directory. Our LDIF file listed names, mail addresses and password hashes. Base64 hid none of it. Values can also point to local files with a file URL, and ldapadd read one in our test. Share an LDIF file only with people you would trust with the data.
Can I edit an LDIF file in a text editor?
Yes, but watch the details. Keep the encoding as UTF-8, keep one empty line between entries and start every folded line with exactly one space. A blank line with one space joined two entries in our test. Use a check script before you import the LDIF file.
What does the double colon mean in an LDIF file?
Two colons mean the value is base64. Values need base64 if they start with a space, a colon or the less than sign. They also need it for bytes beyond ASCII. Base64 is an encoding and not a lock, because one line of Python decodes it.
Why do some lines in an LDIF file start with a space?
A line that starts with one space continues the line above, and the reader removes that space. This is called folding. RFC 2849 allows folding at any point and sets no maximum line length. Our LDIF file folded long values at 76 characters, and OpenLDAP wrapped its own output at 78.
What is the difference between LDIF and LDF files?
They share letters and little else. An LDIF file is a text file of directory entries. An LDF file is the binary transaction log of a SQL Server database, or one of two rarer types. The first lines separate them, because an LDIF file starts with version or dn and is readable.
What is the MIME type of an LDIF file?
Wikipedia lists text/x-ldif and a plain text type. We found no registered entry in the part of the IANA list we could read. The file command printed ASCII text for our intact LDIF file, so it does not name LDIF.
Can an LDIF file change or delete entries?
Yes, if it is a change file. Every record has a changetype line with add, delete, modify or modrdn. RFC 2849 allows one kind per file. We applied a two record change file with ldapmodify, and it replaced a phone number and deleted an entry.
Still Stuck With an LDIF File? Two routes out, and where to look next
Read the error line and follow the seven steps. The cause table lists what to try in order.
Read what an LDIF file can contain, and then the checks before you share.
Is it a SQL Server log? An LDF file records database changes. Our page on LDF files covers it, and the versus part shows how the two differ.
Is it a similar ending? An MDB file is an Access database. Our page on MDB files covers it.
Is the data unknown? Our page on DAT files covers files with no clear type, and the file extension resource library lists many more.
Is your type missing? Send it on the submit a file type page.