~ttx/openldap/lucid-gssapi-495418

« back to all changes in this revision

Viewing changes to contrib/ldapc++/src/LdifReader.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Mathias Gug
  • Date: 2008-07-10 14:45:49 UTC
  • Revision ID: james.westby@ubuntu.com-20080710144549-wck73med0e72gfyo
Tags: upstream-2.4.10
ImportĀ upstreamĀ versionĀ 2.4.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright 2008, OpenLDAP Foundation, All Rights Reserved.
 
3
 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
 
4
 */
 
5
 
 
6
#include "LdifReader.h"
 
7
#include "LDAPMessage.h"
 
8
#include "LDAPEntry.h"
 
9
#include "LDAPAttributeList.h"
 
10
#include "LDAPAttribute.h"
 
11
#include "LDAPUrl.h"
 
12
#include "debug.h"
 
13
 
 
14
#include <string>
 
15
#include <sstream>
 
16
#include <stdexcept>
 
17
 
 
18
#include <sasl/saslutil.h> // For base64 routines
 
19
 
 
20
typedef std::pair<std::string, std::string> stringpair;
 
21
 
 
22
LdifReader::LdifReader( std::istream &input ) 
 
23
        : m_ldifstream(input), m_lineNumber(0)
 
24
{
 
25
    DEBUG(LDAP_DEBUG_TRACE, "<> LdifReader::LdifReader()" << std::endl);
 
26
    this->m_version = 0;
 
27
    // read the first record to find out version and type of the LDIF
 
28
    this->readNextRecord(true);
 
29
    this->m_currentIsFirst = true;
 
30
}
 
31
 
 
32
int LdifReader::readNextRecord( bool first )
 
33
{
 
34
    DEBUG(LDAP_DEBUG_TRACE, "-> LdifReader::readRecord()" << std::endl);
 
35
    std::string line;
 
36
    std::string type;
 
37
    std::string value;
 
38
    int numLine = 0;
 
39
    int recordType = 0;
 
40
 
 
41
    if ( (! first) && this->m_currentIsFirst == true )
 
42
    {
 
43
        this->m_currentIsFirst = false;
 
44
        return m_curRecType;
 
45
    }
 
46
 
 
47
    m_currentRecord.clear();
 
48
 
 
49
    while ( !this->getLdifLine(line) )
 
50
    {
 
51
        DEBUG(LDAP_DEBUG_TRACE, "  Line: " << line << std::endl );
 
52
 
 
53
        // skip comments and empty lines between entries
 
54
        if ( line[0] == '#' || ( numLine == 0 && line.size() == 0 ) )
 
55
        {
 
56
            DEBUG(LDAP_DEBUG_TRACE, "skipping empty line or comment" << std::endl );
 
57
            continue;
 
58
        }
 
59
        if ( line.size() == 0 ) 
 
60
        {
 
61
            // End of Entry
 
62
            break;
 
63
        }
 
64
 
 
65
        this->splitLine(line, type, value);
 
66
 
 
67
        if ( numLine == 0 )
 
68
        {
 
69
            if ( type == "version" )
 
70
            {
 
71
                std::istringstream valuestream(value);
 
72
                valuestream >> this->m_version;
 
73
                if ( this->m_version != 1 ) // there is no other Version than LDIFv1 
 
74
                {
 
75
                    std::ostringstream err;
 
76
                    err << "Line " << this->m_lineNumber 
 
77
                        << ": Unsuported LDIF Version";
 
78
                    throw( std::runtime_error(err.str()) );
 
79
                }
 
80
                continue;
 
81
            }
 
82
            if ( type == "dn" ) // Record should start with the DN ...
 
83
            {
 
84
                DEBUG(LDAP_DEBUG_TRACE, " Record DN:" << value << std::endl);
 
85
            }
 
86
            else if ( type == "include" ) // ... or it might be an "include" line
 
87
            {
 
88
                DEBUG(LDAP_DEBUG_TRACE, " Include directive: " << value << std::endl);
 
89
                if ( this->m_version == 1 )
 
90
                {
 
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()) );
 
95
                }
 
96
                else
 
97
                {
 
98
                    std::ostringstream err;
 
99
                    err << "Line " << this->m_lineNumber 
 
100
                        << ": \"include\" not yet suppported.";
 
101
                    throw( std::runtime_error(err.str()) );
 
102
                }
 
103
            }
 
104
            else
 
105
            {
 
106
                DEBUG(LDAP_DEBUG_TRACE, " Record doesn't start with a DN" 
 
107
                            << std::endl);
 
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()) );
 
112
            }
 
113
        }
 
114
        if ( numLine == 1 ) // might contain "changtype" to indicate a change request
 
115
        {
 
116
            if ( type == "changetype" ) 
 
117
            {
 
118
                if ( first ) 
 
119
                {
 
120
                    this->m_ldifTypeRequest = true;
 
121
                }
 
122
                else if (! this->m_ldifTypeRequest )
 
123
                {
 
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()) );
 
129
                }
 
130
                if ( value == "modify" )
 
131
                {
 
132
                    recordType = LDAPMsg::MODIFY_REQUEST;
 
133
                }
 
134
                else if ( value == "add" )
 
135
                {
 
136
                    recordType = LDAPMsg::ADD_REQUEST;
 
137
                }
 
138
                else if ( value == "delete" )
 
139
                {
 
140
                    recordType = LDAPMsg::DELETE_REQUEST;
 
141
                }
 
142
                else if ( value == "modrdn" )
 
143
                {   
 
144
                    recordType = LDAPMsg::MODRDN_REQUEST;
 
145
                }
 
146
                else
 
147
                {
 
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()) );
 
154
                }
 
155
            }
 
156
            else
 
157
            {
 
158
                if ( first ) 
 
159
                {
 
160
                    this->m_ldifTypeRequest = false;
 
161
                }
 
162
                else if (this->m_ldifTypeRequest )
 
163
                {
 
164
                    // Entry record in Change record LDIF, should we accept 
 
165
                    // it (e.g. as AddRequest)?
 
166
                }
 
167
                recordType = LDAPMsg::SEARCH_ENTRY;
 
168
            }
 
169
        }
 
170
        m_currentRecord.push_back( stringpair(type, value) );
 
171
        numLine++;
 
172
    }
 
173
    DEBUG(LDAP_DEBUG_TRACE, "<- LdifReader::readRecord() return: " 
 
174
            << recordType << std::endl);
 
175
    m_curRecType = recordType;
 
176
    return recordType;
 
177
}
 
178
 
 
179
LDAPEntry LdifReader::getEntryRecord()
 
180
{
 
181
    if ( m_curRecType != LDAPMsg::SEARCH_ENTRY )
 
182
    {
 
183
        // Error
 
184
    }
 
185
    std::list<stringpair>::const_iterator i = m_currentRecord.begin();
 
186
    LDAPEntry resEntry(i->second);
 
187
    i++;
 
188
    LDAPAttribute curAttr(i->first);
 
189
    LDAPAttributeList *curAl = new LDAPAttributeList();
 
190
    for ( ; i != m_currentRecord.end(); i++ )
 
191
    {
 
192
        if ( i->first == curAttr.getName() )
 
193
        {
 
194
            curAttr.addValue(i->second);
 
195
        }
 
196
        else
 
197
        {
 
198
            if ( curAl->getAttributeByName( i->first ) )
 
199
            {
 
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()) );
 
206
            }
 
207
            else
 
208
            {
 
209
                curAl->addAttribute( curAttr );
 
210
                curAttr = LDAPAttribute( i->first, i->second );
 
211
            }
 
212
        }
 
213
    }
 
214
    curAl->addAttribute( curAttr );
 
215
    resEntry.setAttributes( curAl );
 
216
    return resEntry;
 
217
}
 
218
 
 
219
int LdifReader::getLdifLine(std::string &ldifline)
 
220
{
 
221
    DEBUG(LDAP_DEBUG_TRACE, "-> LdifReader::getLdifLine()" << std::endl);
 
222
 
 
223
    this->m_lineNumber++;
 
224
    if ( ! getline(m_ldifstream, ldifline) )
 
225
    {
 
226
        return -1;
 
227
    }
 
228
    while ( m_ldifstream &&
 
229
        (m_ldifstream.peek() == ' ' || m_ldifstream.peek() == '\t'))
 
230
    {
 
231
        std::string cat;
 
232
        m_ldifstream.ignore();
 
233
        getline(m_ldifstream, cat);
 
234
        ldifline += cat;
 
235
        this->m_lineNumber++;
 
236
    }
 
237
 
 
238
    DEBUG(LDAP_DEBUG_TRACE, "<- LdifReader::getLdifLine()" << std::endl);
 
239
    return 0;
 
240
}
 
241
 
 
242
void LdifReader::splitLine(
 
243
            const std::string& line, 
 
244
            std::string &type,
 
245
            std::string &value) const
 
246
{
 
247
    std::string::size_type pos = line.find(':');
 
248
    if ( pos == std::string::npos )
 
249
    {
 
250
        DEBUG(LDAP_DEBUG_ANY, "Invalid LDIF line. No `:` separator" 
 
251
                << std::endl );
 
252
        std::ostringstream err;
 
253
        err << "Line " << this->m_lineNumber << ": Invalid LDIF line. No `:` separator";
 
254
        throw( std::runtime_error( err.str() ));
 
255
    }
 
256
 
 
257
    type = line.substr(0, pos);
 
258
    if ( pos == line.size() )
 
259
    {
 
260
        // empty value
 
261
        value = "";
 
262
        return;
 
263
    }
 
264
 
 
265
    pos++;
 
266
    char delim = line[pos];
 
267
    if ( delim == ':' || delim == '<' )
 
268
    {
 
269
        pos++;
 
270
    }
 
271
 
 
272
    for( ; pos < line.size() && isspace(line[pos]); pos++ )
 
273
    { /* empty */ }
 
274
 
 
275
    value = line.substr(pos);
 
276
 
 
277
    if ( delim == ':' )
 
278
    {
 
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);
 
284
        if( rc == SASL_OK )
 
285
        {
 
286
            value = std::string(outbuf);
 
287
        }
 
288
        else if ( rc == SASL_BADPROT )
 
289
        {
 
290
            value = "";
 
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() ));
 
295
        }
 
296
        else if ( rc == SASL_BUFOVER )
 
297
        {
 
298
            value = "";
 
299
            DEBUG( LDAP_DEBUG_TRACE, " not enough space in output buffer" 
 
300
                    << std::endl );
 
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() ));
 
305
        }
 
306
    }
 
307
    else if ( delim == '<' )
 
308
    {
 
309
        // URL value
 
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() ));
 
315
    }
 
316
    else 
 
317
    {
 
318
        // "normal" value
 
319
        DEBUG(LDAP_DEBUG_TRACE, "  string value" << std::endl );
 
320
    }
 
321
    DEBUG(LDAP_DEBUG_TRACE, "  Type: <" << type << ">" << std::endl );
 
322
    DEBUG(LDAP_DEBUG_TRACE, "  Value: <" << value << ">" << std::endl );
 
323
    return;
 
324
}
 
325
 
 
326
std::string LdifReader::readIncludeLine( const std::string& line ) const
 
327
{
 
328
    std::string::size_type pos = sizeof("file:") - 1;
 
329
    std::string scheme = line.substr( 0, pos );
 
330
    std::string file;
 
331
 
 
332
    // only file:// URLs supported currently
 
333
    if ( scheme != "file:" )
 
334
    {
 
335
        DEBUG( LDAP_DEBUG_TRACE, "unsupported scheme: " << scheme 
 
336
                << std::endl);
 
337
    }
 
338
    else if ( line[pos] == '/' )
 
339
    {
 
340
        if ( line[pos+1] == '/' )
 
341
        {
 
342
            pos += 2;
 
343
        }
 
344
        file = line.substr(pos, std::string::npos);
 
345
        DEBUG( LDAP_DEBUG_TRACE, "target file: " << file << std::endl);
 
346
    }
 
347
    return file;
 
348
}