2
* Copyright 2008, OpenLDAP Foundation, All Rights Reserved.
3
* COPYING RESTRICTIONS APPLY, see COPYRIGHT file
6
#include "LdifReader.h"
7
#include "LDAPMessage.h"
9
#include "LDAPAttributeList.h"
10
#include "LDAPAttribute.h"
18
#include <sasl/saslutil.h> // For base64 routines
20
typedef std::pair<std::string, std::string> stringpair;
22
LdifReader::LdifReader( std::istream &input )
23
: m_ldifstream(input), m_lineNumber(0)
25
DEBUG(LDAP_DEBUG_TRACE, "<> LdifReader::LdifReader()" << std::endl);
27
// read the first record to find out version and type of the LDIF
28
this->readNextRecord(true);
29
this->m_currentIsFirst = true;
32
int LdifReader::readNextRecord( bool first )
34
DEBUG(LDAP_DEBUG_TRACE, "-> LdifReader::readRecord()" << std::endl);
41
if ( (! first) && this->m_currentIsFirst == true )
43
this->m_currentIsFirst = false;
47
m_currentRecord.clear();
49
while ( !this->getLdifLine(line) )
51
DEBUG(LDAP_DEBUG_TRACE, " Line: " << line << std::endl );
53
// skip comments and empty lines between entries
54
if ( line[0] == '#' || ( numLine == 0 && line.size() == 0 ) )
56
DEBUG(LDAP_DEBUG_TRACE, "skipping empty line or comment" << std::endl );
59
if ( line.size() == 0 )
65
this->splitLine(line, type, value);
69
if ( type == "version" )
71
std::istringstream valuestream(value);
72
valuestream >> this->m_version;
73
if ( this->m_version != 1 ) // there is no other Version than LDIFv1
75
std::ostringstream err;
76
err << "Line " << this->m_lineNumber
77
<< ": Unsuported LDIF Version";
78
throw( std::runtime_error(err.str()) );
82
if ( type == "dn" ) // Record should start with the DN ...
84
DEBUG(LDAP_DEBUG_TRACE, " Record DN:" << value << std::endl);
86
else if ( type == "include" ) // ... or it might be an "include" line
88
DEBUG(LDAP_DEBUG_TRACE, " Include directive: " << value << std::endl);
89
if ( this->m_version == 1 )
91
std::ostringstream err;
92
err << "Line " << this->m_lineNumber
93
<< ": \"include\" not allowed in LDIF version 1.";
94
throw( std::runtime_error(err.str()) );
98
std::ostringstream err;
99
err << "Line " << this->m_lineNumber
100
<< ": \"include\" not yet suppported.";
101
throw( std::runtime_error(err.str()) );
106
DEBUG(LDAP_DEBUG_TRACE, " Record doesn't start with a DN"
108
std::ostringstream err;
109
err << "Line " << this->m_lineNumber
110
<< ": LDIF record does not start with a DN.";
111
throw( std::runtime_error(err.str()) );
114
if ( numLine == 1 ) // might contain "changtype" to indicate a change request
116
if ( type == "changetype" )
120
this->m_ldifTypeRequest = true;
122
else if (! this->m_ldifTypeRequest )
124
// Change Request in Entry record LDIF, should we accept it?
125
std::ostringstream err;
126
err << "Line " << this->m_lineNumber
127
<< ": Change Request in an entry-only LDIF.";
128
throw( std::runtime_error(err.str()) );
130
if ( value == "modify" )
132
recordType = LDAPMsg::MODIFY_REQUEST;
134
else if ( value == "add" )
136
recordType = LDAPMsg::ADD_REQUEST;
138
else if ( value == "delete" )
140
recordType = LDAPMsg::DELETE_REQUEST;
142
else if ( value == "modrdn" )
144
recordType = LDAPMsg::MODRDN_REQUEST;
148
DEBUG(LDAP_DEBUG_TRACE, " Unknown change request <"
149
<< value << ">" << std::endl);
150
std::ostringstream err;
151
err << "Line " << this->m_lineNumber
152
<< ": Unknown changetype: \"" << value << "\".";
153
throw( std::runtime_error(err.str()) );
160
this->m_ldifTypeRequest = false;
162
else if (this->m_ldifTypeRequest )
164
// Entry record in Change record LDIF, should we accept
165
// it (e.g. as AddRequest)?
167
recordType = LDAPMsg::SEARCH_ENTRY;
170
m_currentRecord.push_back( stringpair(type, value) );
173
DEBUG(LDAP_DEBUG_TRACE, "<- LdifReader::readRecord() return: "
174
<< recordType << std::endl);
175
m_curRecType = recordType;
179
LDAPEntry LdifReader::getEntryRecord()
181
if ( m_curRecType != LDAPMsg::SEARCH_ENTRY )
185
std::list<stringpair>::const_iterator i = m_currentRecord.begin();
186
LDAPEntry resEntry(i->second);
188
LDAPAttribute curAttr(i->first);
189
LDAPAttributeList *curAl = new LDAPAttributeList();
190
for ( ; i != m_currentRecord.end(); i++ )
192
if ( i->first == curAttr.getName() )
194
curAttr.addValue(i->second);
198
if ( curAl->getAttributeByName( i->first ) )
200
// Attribute exists already -> Syntax Error
201
std::ostringstream err;
202
err << "Line " << this->m_lineNumber
203
<< ": Attribute \"" << i->first
204
<< "\" specified multiple times.";
205
throw( std::runtime_error(err.str()) );
209
curAl->addAttribute( curAttr );
210
curAttr = LDAPAttribute( i->first, i->second );
214
curAl->addAttribute( curAttr );
215
resEntry.setAttributes( curAl );
219
int LdifReader::getLdifLine(std::string &ldifline)
221
DEBUG(LDAP_DEBUG_TRACE, "-> LdifReader::getLdifLine()" << std::endl);
223
this->m_lineNumber++;
224
if ( ! getline(m_ldifstream, ldifline) )
228
while ( m_ldifstream &&
229
(m_ldifstream.peek() == ' ' || m_ldifstream.peek() == '\t'))
232
m_ldifstream.ignore();
233
getline(m_ldifstream, cat);
235
this->m_lineNumber++;
238
DEBUG(LDAP_DEBUG_TRACE, "<- LdifReader::getLdifLine()" << std::endl);
242
void LdifReader::splitLine(
243
const std::string& line,
245
std::string &value) const
247
std::string::size_type pos = line.find(':');
248
if ( pos == std::string::npos )
250
DEBUG(LDAP_DEBUG_ANY, "Invalid LDIF line. No `:` separator"
252
std::ostringstream err;
253
err << "Line " << this->m_lineNumber << ": Invalid LDIF line. No `:` separator";
254
throw( std::runtime_error( err.str() ));
257
type = line.substr(0, pos);
258
if ( pos == line.size() )
266
char delim = line[pos];
267
if ( delim == ':' || delim == '<' )
272
for( ; pos < line.size() && isspace(line[pos]); pos++ )
275
value = line.substr(pos);
279
// Base64 encoded value
280
DEBUG(LDAP_DEBUG_TRACE, " base64 encoded value" << std::endl );
281
char outbuf[value.size()];
282
int rc = sasl_decode64(value.c_str(), value.size(),
283
outbuf, value.size(), NULL);
286
value = std::string(outbuf);
288
else if ( rc == SASL_BADPROT )
291
DEBUG( LDAP_DEBUG_TRACE, " invalid base64 content" << std::endl );
292
std::ostringstream err;
293
err << "Line " << this->m_lineNumber << ": Can't decode Base64 data";
294
throw( std::runtime_error( err.str() ));
296
else if ( rc == SASL_BUFOVER )
299
DEBUG( LDAP_DEBUG_TRACE, " not enough space in output buffer"
301
std::ostringstream err;
302
err << "Line " << this->m_lineNumber
303
<< ": Can't decode Base64 data. Buffer too small";
304
throw( std::runtime_error( err.str() ));
307
else if ( delim == '<' )
310
DEBUG(LDAP_DEBUG_TRACE, " url value" << std::endl );
311
std::ostringstream err;
312
err << "Line " << this->m_lineNumber
313
<< ": URLs are currently not supported";
314
throw( std::runtime_error( err.str() ));
319
DEBUG(LDAP_DEBUG_TRACE, " string value" << std::endl );
321
DEBUG(LDAP_DEBUG_TRACE, " Type: <" << type << ">" << std::endl );
322
DEBUG(LDAP_DEBUG_TRACE, " Value: <" << value << ">" << std::endl );
326
std::string LdifReader::readIncludeLine( const std::string& line ) const
328
std::string::size_type pos = sizeof("file:") - 1;
329
std::string scheme = line.substr( 0, pos );
332
// only file:// URLs supported currently
333
if ( scheme != "file:" )
335
DEBUG( LDAP_DEBUG_TRACE, "unsupported scheme: " << scheme
338
else if ( line[pos] == '/' )
340
if ( line[pos+1] == '/' )
344
file = line.substr(pos, std::string::npos);
345
DEBUG( LDAP_DEBUG_TRACE, "target file: " << file << std::endl);