Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 :
21 : #include "ldapaccess.hxx"
22 :
23 : #include <boost/noncopyable.hpp>
24 :
25 : #include <osl/diagnose.h>
26 : #include <rtl/ustrbuf.hxx>
27 : #include <rtl/strbuf.hxx>
28 :
29 :
30 : namespace extensions { namespace config { namespace ldap {
31 :
32 :
33 : typedef int LdapErrCode;
34 :
35 : struct LdapMessageHolder: private boost::noncopyable
36 : {
37 0 : LdapMessageHolder() : msg(0) {}
38 0 : ~LdapMessageHolder()
39 : {
40 0 : if (msg)
41 0 : ldap_msgfree(msg);
42 0 : }
43 :
44 : LDAPMessage * msg;
45 : };
46 :
47 0 : LdapConnection::~LdapConnection()
48 : {
49 0 : if (isValid()) disconnect();
50 0 : }
51 :
52 :
53 0 : void LdapConnection::disconnect()
54 : {
55 0 : if (mConnection != NULL)
56 : {
57 0 : ldap_unbind_s(mConnection) ;
58 0 : mConnection = NULL;
59 : }
60 0 : }
61 :
62 :
63 0 : static void checkLdapReturnCode(const sal_Char *aOperation,
64 : LdapErrCode aRetCode,
65 : LDAP * /*aConnection*/)
66 : {
67 0 : if (aRetCode == LDAP_SUCCESS) { return ; }
68 :
69 : static const sal_Char *kNoSpecificMessage = "No additional information" ;
70 0 : OUStringBuffer message ;
71 :
72 0 : if (aOperation != NULL)
73 : {
74 0 : message.appendAscii(aOperation).appendAscii(": ") ;
75 : }
76 0 : message.appendAscii(ldap_err2string(aRetCode)).appendAscii(" (") ;
77 0 : sal_Char *stub = NULL ;
78 :
79 : #ifndef LDAP_OPT_SIZELIMIT // for use with OpenLDAP
80 : ldap_get_lderrno(aConnection, NULL, &stub) ;
81 : #endif
82 0 : if (stub != NULL)
83 : {
84 0 : message.appendAscii(stub) ;
85 : // It would seem the message returned is actually
86 : // not a copy of a string but rather some static
87 : // string itself. At any rate freeing it seems to
88 : // cause some undue problems at least on Windows.
89 : // This call is thus disabled for the moment.
90 : //ldap_memfree(stub) ;
91 : }
92 0 : else { message.appendAscii(kNoSpecificMessage) ; }
93 0 : message.appendAscii(")") ;
94 : throw ldap::LdapGenericException(message.makeStringAndClear(),
95 0 : NULL, aRetCode) ;
96 : }
97 :
98 0 : void LdapConnection::connectSimple(const LdapDefinition& aDefinition)
99 : throw (ldap::LdapConnectionException, ldap::LdapGenericException)
100 : {
101 : OSL_ENSURE(!isValid(), "Recoonecting an LDAP connection that is already established");
102 0 : if (isValid()) disconnect();
103 :
104 0 : mLdapDefinition = aDefinition;
105 0 : connectSimple();
106 0 : }
107 :
108 0 : void LdapConnection::connectSimple()
109 : throw (ldap::LdapConnectionException, ldap::LdapGenericException)
110 : {
111 0 : if (!isValid())
112 : {
113 : // Connect to the server
114 0 : initConnection() ;
115 : // Set Protocol V3
116 0 : int version = LDAP_VERSION3;
117 : ldap_set_option(mConnection,
118 : LDAP_OPT_PROTOCOL_VERSION,
119 0 : &version);
120 :
121 : #ifdef LDAP_X_OPT_CONNECT_TIMEOUT // OpenLDAP doesn't support this and the func
122 : /* timeout is specified in milliseconds -> 4 seconds*/
123 : int timeout = 4000;
124 : #ifdef WNT
125 : ldap_set_optionW( mConnection,
126 : LDAP_X_OPT_CONNECT_TIMEOUT,
127 : &timeout );
128 : #else
129 : ldap_set_option( mConnection,
130 : LDAP_X_OPT_CONNECT_TIMEOUT,
131 : &timeout );
132 : #endif
133 : #endif
134 :
135 : // Do the bind
136 : #ifdef WNT
137 : LdapErrCode retCode = ldap_simple_bind_sW(mConnection,
138 : (PWCHAR) mLdapDefinition.mAnonUser.getStr(),
139 : (PWCHAR) mLdapDefinition.mAnonCredentials.getStr() );
140 : #else
141 : LdapErrCode retCode = ldap_simple_bind_s(mConnection,
142 : OUStringToOString( mLdapDefinition.mAnonUser, RTL_TEXTENCODING_UTF8 ).getStr(),
143 0 : OUStringToOString( mLdapDefinition.mAnonCredentials, RTL_TEXTENCODING_UTF8 ).getStr()) ;
144 : #endif
145 :
146 0 : checkLdapReturnCode("SimpleBind", retCode, mConnection) ;
147 : }
148 0 : }
149 :
150 0 : void LdapConnection::initConnection()
151 : throw (ldap::LdapConnectionException)
152 : {
153 0 : if (mLdapDefinition.mServer.isEmpty())
154 : {
155 0 : OUStringBuffer message ;
156 :
157 0 : message.appendAscii("Cannot initialise connection to LDAP: No server specified.") ;
158 0 : throw ldap::LdapConnectionException(message.makeStringAndClear()) ;
159 : }
160 :
161 0 : if (mLdapDefinition.mPort == 0) mLdapDefinition.mPort = LDAP_PORT;
162 :
163 : #ifdef WNT
164 : mConnection = ldap_initW((PWCHAR) mLdapDefinition.mServer.getStr(),
165 : mLdapDefinition.mPort) ;
166 : #else
167 : mConnection = ldap_init(OUStringToOString( mLdapDefinition.mServer, RTL_TEXTENCODING_UTF8 ).getStr(),
168 0 : mLdapDefinition.mPort) ;
169 : #endif
170 0 : if (mConnection == NULL)
171 : {
172 0 : OUStringBuffer message ;
173 :
174 0 : message.appendAscii("Cannot initialise connection to LDAP server ") ;
175 0 : message.append(mLdapDefinition.mServer) ;
176 0 : message.appendAscii(":") ;
177 0 : message.append(mLdapDefinition.mPort) ;
178 0 : throw ldap::LdapConnectionException(message.makeStringAndClear());
179 : }
180 0 : }
181 :
182 0 : void LdapConnection::getUserProfile(
183 : const OUString& aUser, LdapData * data)
184 : throw (lang::IllegalArgumentException,
185 : ldap::LdapConnectionException, ldap::LdapGenericException)
186 : {
187 : OSL_ASSERT(data != 0);
188 0 : if (!isValid()) { connectSimple(); }
189 :
190 0 : OUString aUserDn =findUserDn( aUser );
191 :
192 0 : LdapMessageHolder result;
193 : #ifdef WNT
194 : LdapErrCode retCode = ldap_search_sW(mConnection,
195 : (PWCHAR) aUserDn.getStr(),
196 : LDAP_SCOPE_BASE,
197 : const_cast<PWCHAR>( L"(objectclass=*)" ),
198 : 0,
199 : 0, // Attributes + values
200 : &result.msg) ;
201 : #else
202 : LdapErrCode retCode = ldap_search_s(mConnection,
203 : OUStringToOString( aUserDn, RTL_TEXTENCODING_UTF8 ).getStr(),
204 : LDAP_SCOPE_BASE,
205 : "(objectclass=*)",
206 : 0,
207 : 0, // Attributes + values
208 0 : &result.msg) ;
209 : #endif
210 0 : checkLdapReturnCode("getUserProfile", retCode,mConnection) ;
211 :
212 : BerElement * ptr;
213 : #ifdef WNT
214 : PWCHAR attr = ldap_first_attributeW(mConnection, result.msg, &ptr);
215 : while (attr) {
216 : PWCHAR * values = ldap_get_valuesW(mConnection, result.msg, attr);
217 : if (values) {
218 : const OUString aAttr( reinterpret_cast<sal_Unicode*>( attr ) );
219 : const OUString aValues( reinterpret_cast<sal_Unicode*>( *values ) );
220 : data->insert(
221 : LdapData::value_type( aAttr, aValues ));
222 : ldap_value_freeW(values);
223 : }
224 : attr = ldap_next_attributeW(mConnection, result.msg, ptr);
225 : #else
226 0 : char * attr = ldap_first_attribute(mConnection, result.msg, &ptr);
227 0 : while (attr) {
228 0 : char ** values = ldap_get_values(mConnection, result.msg, attr);
229 0 : if (values) {
230 : data->insert(
231 : LdapData::value_type(
232 : OStringToOUString(attr, RTL_TEXTENCODING_ASCII_US),
233 0 : OStringToOUString(*values, RTL_TEXTENCODING_UTF8)));
234 0 : ldap_value_free(values);
235 : }
236 0 : attr = ldap_next_attribute(mConnection, result.msg, ptr);
237 : #endif
238 0 : }
239 0 : }
240 :
241 0 : OUString LdapConnection::findUserDn(const OUString& aUser)
242 : throw (lang::IllegalArgumentException,
243 : ldap::LdapConnectionException, ldap::LdapGenericException)
244 : {
245 0 : if (!isValid()) { connectSimple(); }
246 :
247 0 : if (aUser.isEmpty())
248 : {
249 : throw lang::IllegalArgumentException(
250 : "LdapConnection::findUserDn -User id is empty",
251 0 : NULL, 0) ;
252 : }
253 :
254 :
255 :
256 0 : OUStringBuffer filter( "(&(objectclass=" );
257 :
258 0 : filter.append( mLdapDefinition.mUserObjectClass ).append(")(") ;
259 0 : filter.append( mLdapDefinition.mUserUniqueAttr ).append("=").append(aUser).append("))") ;
260 :
261 0 : LdapMessageHolder result;
262 : #ifdef WNT
263 : PWCHAR attributes [2] = { const_cast<PWCHAR>( L"1.1" ), NULL };
264 : LdapErrCode retCode = ldap_search_sW(mConnection,
265 : (PWCHAR) mLdapDefinition.mBaseDN.getStr(),
266 : LDAP_SCOPE_SUBTREE,
267 : (PWCHAR) filter.makeStringAndClear().getStr(), attributes, 0, &result.msg) ;
268 : #else
269 0 : sal_Char * attributes [2] = { const_cast<sal_Char *>(LDAP_NO_ATTRS), NULL };
270 : LdapErrCode retCode = ldap_search_s(mConnection,
271 : OUStringToOString( mLdapDefinition.mBaseDN, RTL_TEXTENCODING_UTF8 ).getStr(),
272 : LDAP_SCOPE_SUBTREE,
273 0 : OUStringToOString( filter.makeStringAndClear(), RTL_TEXTENCODING_UTF8 ).getStr(), attributes, 0, &result.msg) ;
274 : #endif
275 0 : checkLdapReturnCode("FindUserDn", retCode,mConnection) ;
276 0 : OUString userDn ;
277 0 : LDAPMessage *entry = ldap_first_entry(mConnection, result.msg) ;
278 :
279 0 : if (entry != NULL)
280 : {
281 : #ifdef WNT
282 : PWCHAR charsDn = ldap_get_dnW(mConnection, entry) ;
283 :
284 : userDn = OUString( reinterpret_cast<const sal_Unicode*>( charsDn ) );
285 : ldap_memfreeW(charsDn) ;
286 : #else
287 0 : sal_Char *charsDn = ldap_get_dn(mConnection, entry) ;
288 :
289 0 : userDn = OStringToOUString( charsDn, RTL_TEXTENCODING_UTF8 );
290 0 : ldap_memfree(charsDn) ;
291 : #endif
292 : }
293 : else
294 : {
295 : OSL_FAIL( "LdapConnection::findUserDn-could not get DN for User ");
296 : }
297 :
298 0 : return userDn ;
299 : }
300 :
301 :
302 :
303 : } } } // extensions.config.ldap
304 :
305 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|