Issue #1258 - Part 1: Import mailnews, ldap, and mork from comm-esr52.9.1

This commit is contained in:
Matt A. Tobin 2019-11-03 00:17:46 -04:00 • committed by Roy Tam
commit e400f4130a
1564 changed files with 510348 additions and 0 deletions

24
ldap/xpcom/README.txt Normal file
View file

@ -0,0 +1,24 @@
This is the home for XPCOM modules that implement LDAP functionality.
What's Here
-----------
base/
Implements a wrapper around the LDAP C SDK, as well as support
for ldap: URLs in the browser. Written entirely in C++;
theoretically only depends on necko, xpcom, nspr, and the LDAP
C SDK.
datasource/
An RDF datasource, written in Javascript.
tests/
Some basic tests to help ensure that things don't break as
development proceeds. Currently, there is only some stuff for
testing the datasource.
Building
--------
See <http://www.mozilla.org/directory/xpcom.html>.
Dan Mosedale <dmose@mozilla.org>

155
ldap/xpcom/TODO.txt Normal file
View file

@ -0,0 +1,155 @@
housecleaning for first 0.x release
-----------------------------------
* error handling: sort out what should be NS_ASSERTIONs vs. normal
error conditions (eg network & data errors), especially in nsLDAPChannel.
also shouldn't be casting results of nsILDAPConnection::GetErrorString to
void in ldapSearch. (ideally this would use xpidl nsresult decls
(bug 13423), but that's not done yet). This also requires some
threadsafety work related to the data and interfaces touched by
nsLDAPChannel::Cancel, since these are used in the connection
callbacks, and we also need to be able to cancel from the connection
callbacks themselves.
* audit for and fix leaks / bloat
* destroy connection & thread when done with it; deal with timeouts
(blocked on LDAP C SDK 4.1, in the hopes that the NSPR
binding of the IO functions will provide us with some way to pop out
of the select() that's called under ldap_result(). It may not be worth
implementing this until nsLDAPService is resurrected. If this
doesn't work, we may have to give nsLDAPConnection an event queue &
loop of its own, instead of using the LDAP C SDK as a vector to get
events over there.
items blocked waiting for other work
------------------------------------
* go through the various options that can be used with the SDK function
ldap_set_options() and decide if and where the various functions should
be used. This will include memory allocator settings, and possibly
threadsafety callbacks (if necessary). (blocked waiting on LDAP C
SDK 4.1 to land, since it contains NSPR bindings for some of this).
* searches that return lots of entries to the nsLDAPChannel
(eg (sn=Smith) at netcenter) mostly stall out the UI. moving most of the
callback work off the UI thread to the LDAP connection thread didn't
help; so this seems to be lossage in the event system itself (bug 50104).
* deal with race condition that happens if data comes back after
nsLDAPChannel::Cancel is called. AsyncStreamListener expects
GetStatus to return OK, and asserts when it doesn't. (blocked waiting
on insight from Warren about nsSocketTransport's use of mCancelStatus).
* ensure that multiple calls to Cancel don't do the wrong thing
* move the ldap_unbind() call out of the nsLDAPConnection destructor,
since nsLDAPConnection will soon go back to being callable from the
UI thread, and ldap_unbind() is actually synchronous. additionally,
arrange for the connection thread to shutdown. (waiting for
nsILDAPService to be implemented on the theory that nsILDAPService
might have it's own thread and it would be reasonable to call
ldap_unbind() from that thread).
* currently nsILDAPOperation::SimpleBind is called as though it were
asynchronous (ie from the UI thread), which it mostly is -- the call
to connect() can stall. We could use the ASYNC_CONNECT flag, but it
seems to do weird stuff on Linux, and mcs says it isn't well tested
anyway. At the moment, my feeling is that fixing ASYNC_CONNECT is
probably the right thing to do, but the bind could actually be
pushed from nsILDAPOperation into nsILDAPConnection and then called
after the thread for the connection is spun up (waiting on help from
the LDAP SDK folks: bug 50074).
misc
----
* verify that ldap_parse_result() and ldap_get_ldaperrno() aren't
required to be called from the same thread as ldap_result() and
before the thread-specific ldaperrno has a chance to change. Note:
now that ldap_parse_result is only called inside the initializer
nsLDAPMessage::Init(), this is probably no longer an issue there at
least. Need to confirm.
* replace instances of (obsolete) |static NS_DEFINE_IID| variables
with direct calls to NS_GET_IID in the code.
* investigate use of DNS in LDAP sdk. I think sync functions used in the
wrong places (eg they end up getting called from Mozilla on the UI thread)?
* audit for and implement any appropriate NOT_IMPLEMENTED functions
* re-read the IDL for interfaces implemented by nsLDAPChannel.cpp make sure
all interfaces are implemented correctly
* implement progress info interfaces, if possible (% done)
* investigate the MOZILLA_CLIENT define as used by the SDK. eg do we still
want the reference to "xp_sort.h"?
* i18n / l10n (any text strings)
* cachability of nsILDAPChannel content: browser cache? ldap_memcache? both?
* use a rebind_proc?
* HTMLize nsLDAPChannel output for linkification
* the LDAP SDK returns UTF8, but I think nsILDAPChannel is handing it
off to callers as ASCII. How does this all relate to the stated
UCS2 policy in Mozilla?
* all attributes are assumed to be strings right now. This probably
needs to change: assume all attributes are binary, use some
heuristic to figure out if they're a string. I wonder how
ldapsearch does this.
* grep for XXXs and fix the issues
rdf datasource
--------------
* revamp nsILDAPService (currently unused code) to manage LDAP
connections and allow for sharing connections between browser
clients. I think this should obviate the need to hold onto the
connection with a delegate factory.
* non-anonymous binding (ie nsLDAPURL supports x-bind-name -- I
suspect this may come with the LDAP C SDK version after 4.1,
though.)
testing
-------
* see how the browser copes when it does such a big search that the server
only returns partial results and an error.
perf
----
* rather than having one thread per nsILDAPConnection, have multiple
nsILDAPConnections share the same thread. possibly pre-spin up a
thread-pool to handle this?
* nsLDAPService: assuming that we do the above and start using
nsLDAPService again, need to implement shutdown for nsLDAPService
(probably analogous to the way nsSocketTransportService shuts down.
but how does nsIShutdownListener fit in here? and CanUnload?)
* remove any unnecessary thread-safety code (NS_IMPL_THREADSAFE) to avoid
locking overhead. need to figure out if everything must be
threadsafe or not.
later
-----
* rationalize the logging strategy. right now there is a mix of
PR_LOG/NS{WARNING|ERROR} and nsIConsoleService and non-logging,
as I have been vacillating on how much logging it's really important to have
(part of my thought process about the XPCOM-wrapper being part of
Mozilla-as-platform)
* get rid of inappropriate use of nsVoidKey by implementing an nsPRInt32Key
* handle referrals
* failover
* addressbook/mail UI glue
* PSM certs from directory glue(?)
* secure (& proxied/socksified?) ldap
* make the LDAP C SDK autoconf glue not be a shim and not require
nsprpub build infrastructure. requires work with the LDAP C SDK
owners, and shouldn't this shouldn't happen until after the most
current ldap SDK code lands in mozilla.org anyway.
* figure out our strategy for LDAPv2 vs. LDAPv3. right now, the code just
uses the C SDK's default of always advertising itself as LDAPv2.

9
ldap/xpcom/moz.build Normal file
View file

@ -0,0 +1,9 @@
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DIRS += [
'public',
'src',
]

View file

@ -0,0 +1,27 @@
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
XPIDL_SOURCES += [
'nsILDAPBERElement.idl',
'nsILDAPBERValue.idl',
'nsILDAPConnection.idl',
'nsILDAPControl.idl',
'nsILDAPErrors.idl',
'nsILDAPMessage.idl',
'nsILDAPMessageListener.idl',
'nsILDAPModification.idl',
'nsILDAPOperation.idl',
'nsILDAPServer.idl',
'nsILDAPService.idl',
'nsILDAPURL.idl',
]
if CONFIG['MOZ_PREF_EXTENSIONS']:
XPIDL_SOURCES += [
'nsILDAPSyncQuery.idl',
]
XPIDL_MODULE = 'mozldap'

View file

@ -0,0 +1,122 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
interface nsILDAPBERValue;
/**
* nsILDAPBERElement is a wrapper interface for a C-SDK BerElement object.
* Typically, this is used as an intermediate object to aid in the manual
* construction of a BER value. Once the construction is completed by calling
* methods on this object, an nsILDAPBERValue can be retrieved from the
* asValue attribute on this interface.
*
* <http://www.mozilla.org/directory/ietf-docs/draft-ietf-ldapext-ldap-c-api-05.txt>
* contains some documentation that mostly (but not exactly) matches
* the code that this wraps in section 17.
*/
[scriptable, uuid(409f5b31-c062-4d11-a35b-0a09e7967bf2)]
interface nsILDAPBERElement : nsISupports
{
/**
* Initialize this object. Must be called before calling any other method
* on this interface.
*
* @param aValue value to preinitialize with; 0 for a new empty object
*
* @exception NS_ERROR_NOT_IMPLEMENTED preinitialization is currently
* not implemented
* @exception NS_ERROR_OUT_OF_MEMORY unable to allocate the internal
* BerElement
*/
void init(in nsILDAPBERValue aValue);
/**
* Most TAG_* constants can be used in the construction or passing in of
* values to the aTag arguments to most of the methods in this interface.
*/
/**
* When returned from a parsing method, 0xffffffff is referred to
* has the parse-error semantic (ie TAG_LBER_ERROR); when passing it to
* a construction method, it is used to mean "pick the default tag for
* this type" (ie TAG_LBER_DEFAULT).
*/
const unsigned long TAG_LBER_ERROR = 0xffffffff;
const unsigned long TAG_LBER_DEFAULT = 0xffffffff;
const unsigned long TAG_LBER_END_OF_SEQORSET = 0xfffffffe;
/**
* BER encoding types and masks
*/
const unsigned long TAG_LBER_PRIMITIVE = 0x00;
/**
* The following two tags are carried over from the LDAP C SDK; their
* exact purpose there is not well documented. They both have
* the same value there as well.
*/
const unsigned long TAG_LBER_CONSTRUCTED = 0x20;
const unsigned long TAG_LBER_ENCODING_MASK = 0x20;
const unsigned long TAG_LBER_BIG_TAG_MASK = 0x1f;
const unsigned long TAG_LBER_MORE_TAG_MASK = 0x80;
/**
* general BER types we know about
*/
const unsigned long TAG_LBER_BOOLEAN = 0x01;
const unsigned long TAG_LBER_INTEGER = 0x02;
const unsigned long TAG_LBER_BITSTRING = 0x03;
const unsigned long TAG_LBER_OCTETSTRING = 0x04;
const unsigned long TAG_LBER_NULL = 0x05;
const unsigned long TAG_LBER_ENUMERATED = 0x0a;
const unsigned long TAG_LBER_SEQUENCE = 0x30;
const unsigned long TAG_LBER_SET = 0x31;
/**
* Write a string to this element.
*
* @param aString string to write
* @param aTag tag for this string (if TAG_LBER_DEFAULT is used,
* TAG_LBER_OCTETSTRING will be written).
*
* @return number of bytes written
*
* @exception NS_ERROR_FAILUE C-SDK returned error
*/
unsigned long putString(in AUTF8String aString, in unsigned long aTag);
/**
* Start a set. Sets may be nested.
*
* @param aTag tag for this set (if TAG_LBER_DEFAULT is used,
* TAG_LBER_SET will be written).
*
* @exception NS_ERROR_FAILUE C-SDK returned an error
*/
void startSet(in unsigned long aTag);
/**
* Cause the entire set started by the last startSet() call to be written.
*
* @exception NS_ERROR_FAILUE C-SDK returned an error
*
* @return number of bytes written
*/
unsigned long putSet();
/**
* an nsILDAPBERValue version of this element. Calls ber_flatten() under
* the hood.
*
* @exception NS_ERROR_OUT_OF_MEMORY
*/
readonly attribute nsILDAPBERValue asValue;
};

View file

@ -0,0 +1,44 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
/**
* Representation of a BER value as an interface containing an array of
* bytes. Someday this should perhaps be obsoleted by a better, more
* generalized version of nsIByteBuffer, but that's currently not even
* scriptable (see bug 125596).
*/
[scriptable, uuid(c817c5fe-1dd1-11b2-a10b-ae9885762ea9)]
interface nsILDAPBERValue : nsISupports
{
/**
* Set the BER value from an array of bytes (copies).
*
* @exception NS_ERROR_OUT_OF_MEMORY couldn't allocate buffer to copy to
*/
void set(in unsigned long aCount,
[array, size_is(aCount)] in octet aValue);
/**
* Set the BER value from a UTF8 string (copies).
*
* @exception NS_ERROR_OUT_OF_MEMORY couldn't allocate buffer to copy to
*/
void setFromUTF8(in AUTF8String aValue);
/**
* Get the BER value as an array of bytes. Note that if this value is
* zero-length, aCount and aRetVal will both be 0. This means that
* (in C++ anyway) the caller MUST test either aCount or aRetval before
* dereferencing aRetVal.
*
* @exception NS_ERROR_OUT_OF_MEMORY couldn't allocate buffer to copy to
*/
void get(out unsigned long aCount,
[retval, array, size_is(aCount)] out octet aRetVal);
};

View file

@ -0,0 +1,77 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
interface nsILDAPOperation;
interface nsILDAPMessageListener;
interface nsILDAPURL;
%{C++
#define NS_LDAPCONNECTION_CONTRACTID "@mozilla.org/network/ldap-connection;1"
%}
[scriptable, uuid(360c1ff7-15e3-4ffe-b4b8-0eda72ebc096)]
interface nsILDAPConnection : nsISupports
{
/**
* the string version of lderrno
*/
readonly attribute wstring errorString;
/**
* DN to bind as. use the init() method to set this.
*
* @exception NS_ERROR_OUT_OF_MEMORY
*/
readonly attribute AUTF8String bindName;
/**
* private parameter (anything caller desires)
*/
attribute nsISupports closure;
/**
* Set up the connection. Note that init() must be called on a thread
* that already has an nsIEventQueue.
*
* @param aUrl A URL for the ldap server. The host, port and
* ssl connection type will be extracted from this
* @param aBindName DN to bind as
* @param aMessageListener Callback for DNS resolution completion
* @param aClosure private parameter (anything caller desires)
* @param aVersion LDAP version to use (currently VERSION2 or
* VERSION3)
*
* @exception NS_ERROR_ILLEGAL_VALUE null pointer or invalid version
* @exception NS_ERROR_OUT_OF_MEMORY ran out of memory
* @exception NS_ERROR_OFFLINE we are in off-line mode
* @exception NS_ERROR_FAILURE
* @exception NS_ERROR_UNEXPECTED internal error
*/
void init(in nsILDAPURL aUrl,
in AUTF8String aBindName,
in nsILDAPMessageListener aMessageListener,
in nsISupports aClosure, in unsigned long aVersion);
const unsigned long VERSION2 = 2;
const unsigned long VERSION3 = 3;
/**
* Get information about the last error that occured on this connection.
*
* @param matched if the server is returning LDAP_NO_SUCH_OBJECT,
* LDAP_ALIAS_PROBLEM, LDAP_INVALID_DN_SYNTAX,
* or LDAP_ALIAS_DEREF_PROBLEM, this will contain
* the portion of DN that matches the entry that is
* closest to the requested entry
*
* @param s additional error information from the server
*
* @return the error code, as defined in nsILDAPErrors.idl
*/
long getLdErrno(out AUTF8String matched, out AUTF8String s);
};

View file

@ -0,0 +1,45 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
interface nsILDAPBERValue;
/**
* XPCOM representation of the C SDK LDAPControl structure.
*/
[scriptable, uuid(3a7ceb8e-482a-4a4f-9aa4-26b9a69a3595)]
interface nsILDAPControl : nsISupports
{
/**
* Control type, represented as a string.
*
* @exceptions none
*/
attribute ACString oid;
/**
* The data associated with a control, if any. To specify that no data
* is to be associated with the control, don't set this at all (which
* is equivalent to setting it to null).
*
* @note Specifying a zero-length value is not currently supported. At some
* date, setting this to an nsILDAPBERValue which has not had any of the
* set methods called will be the appropriate way to do that.
*
* @exceptions none
*/
attribute nsILDAPBERValue value;
/**
* Should the client or server abort if the control is not understood?
* Should be set to false for server controls used in abandon and unbind
* operations, since those have no server response.
*
* @exceptions none
*/
attribute boolean isCritical;
};

View file

@ -0,0 +1,447 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
/**
* Error codes used in the LDAP XPCOM SDK.
*
* Taken from the Mozilla C SDK's ldap.h include file, these should be
* the same as those specified in the draft-ietf-ldapext-ldap-c-api-04.txt
* Internet Draft.
*
* The only good documentation I'm aware of for these error codes is
* at <http://docs.iplanet.com/docs/manuals/directory.html#SDKC>.
* Unfortunately, this does not currently seem to be available under any
* open source license, so I can't include that documentation here as
* doxygen comments.
*
*/
[scriptable, uuid(f9ac10fa-1dd1-11b2-9798-8d5cbda95d74)]
interface nsILDAPErrors : nsISupports
{
const long SUCCESS = 0x00;
const long OPERATIONS_ERROR = 0x01;
const long PROTOCOL_ERROR = 0x02;
const long TIMELIMIT_EXCEEDED = 0x03;
const long SIZELIMIT_EXCEEDED = 0x04;
const long COMPARE_FALSE = 0x05;
const long COMPARE_TRUE = 0x06;
const long STRONG_AUTH_NOT_SUPPORTED = 0x07;
const long STRONG_AUTH_REQUIRED = 0x08;
/**
* UMich LDAPv2 extension
*/
const long PARTIAL_RESULTS = 0x09;
/**
* new in LDAPv3
*/
const long REFERRAL = 0x0a;
/**
* new in LDAPv3
*/
const long ADMINLIMIT_EXCEEDED = 0x0b;
/**
* new in LDAPv3
*/
const long UNAVAILABLE_CRITICAL_EXTENSION = 0x0c;
/**
* new in LDAPv3
*/
const long CONFIDENTIALITY_REQUIRED = 0x0d;
/**
* new in LDAPv3
*/
const long SASL_BIND_IN_PROGRESS = 0x0e;
const long NO_SUCH_ATTRIBUTE = 0x10;
const long UNDEFINED_TYPE = 0x11;
const long INAPPROPRIATE_MATCHING = 0x12;
const long CONSTRAINT_VIOLATION = 0x13;
const long TYPE_OR_VALUE_EXISTS = 0x14;
const long INVALID_SYNTAX = 0x15;
const long NO_SUCH_OBJECT = 0x20;
const long ALIAS_PROBLEM = 0x21;
const long INVALID_DN_SYNTAX = 0x22;
/**
* not used in LDAPv3
*/
const long IS_LEAF = 0x23;
const long ALIAS_DEREF_PROBLEM = 0x24;
const long INAPPROPRIATE_AUTH = 0x30;
const long INVALID_CREDENTIALS = 0x31;
const long INSUFFICIENT_ACCESS = 0x32;
const long BUSY = 0x33;
const long UNAVAILABLE = 0x34;
const long UNWILLING_TO_PERFORM = 0x35;
const long LOOP_DETECT = 0x36;
/**
* server side sort extension
*/
const long SORT_CONTROL_MISSING = 0x3C;
/**
* VLV extension
*/
const long INDEX_RANGE_ERROR = 0x3D;
const long NAMING_VIOLATION = 0x40;
const long OBJECT_CLASS_VIOLATION = 0x41;
const long NOT_ALLOWED_ON_NONLEAF = 0x42;
const long NOT_ALLOWED_ON_RDN = 0x43;
const long ALREADY_EXISTS = 0x44;
const long NO_OBJECT_CLASS_MODS = 0x45;
/**
* reserved CLDAP
*/
const long RESULTS_TOO_LARGE = 0x46;
/**
* new in LDAPv3
*/
const long AFFECTS_MULTIPLE_DSAS = 0x47;
const long OTHER = 0x50;
const long SERVER_DOWN = 0x51;
const long LOCAL_ERROR = 0x52;
const long ENCODING_ERROR = 0x53;
const long DECODING_ERROR = 0x54;
const long TIMEOUT = 0x55;
const long AUTH_UNKNOWN = 0x56;
const long FILTER_ERROR = 0x57;
const long USER_CANCELLED = 0x58;
const long PARAM_ERROR = 0x59;
const long NO_MEMORY = 0x5a;
const long CONNECT_ERROR = 0x5b;
/**
* new in LDAPv3
*/
const long NOT_SUPPORTED = 0x5c;
/**
* new in LDAPv3
*/
const long CONTROL_NOT_FOUND = 0x5d;
/**
* new in LDAPv3
*/
const long NO_RESULTS_RETURNED = 0x5e;
/**
* new in LDAPv3
*/
const long MORE_RESULTS_TO_RETURN = 0x5f;
/**
* new in LDAPv3
*/
const long CLIENT_LOOP = 0x60;
/**
* new in LDAPv3
*/
const long REFERRAL_LIMIT_EXCEEDED = 0x61;
};
/*
* Map these errors codes into the nsresult namespace in C++
*/
%{C++
#define NS_ERROR_LDAP_OPERATIONS_ERROR \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::OPERATIONS_ERROR)
#define NS_ERROR_LDAP_PROTOCOL_ERROR \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::PROTOCOL_ERROR)
#define NS_ERROR_LDAP_TIMELIMIT_EXCEEDED \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::TIMELIMIT_EXCEEDED)
#define NS_ERROR_LDAP_SIZELIMIT_EXCEEDED \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::SIZELIMIT_EXCEEDED)
#define NS_ERROR_LDAP_COMPARE_FALSE \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::COMPARE_FALSE)
#define NS_ERROR_LDAP_COMPARE_TRUE \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::COMPARE_TRUE)
#define NS_ERROR_LDAP_STRONG_AUTH_NOT_SUPPORTED \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::STRONG_AUTH_NOT_SUPPORTED)
#define NS_ERROR_LDAP_STRONG_AUTH_REQUIRED \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::STRONG_AUTH_REQUIRED)
#define NS_ERROR_LDAP_PARTIAL_RESULTS \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::PARTIAL_RESULTS)
#define NS_ERROR_LDAP_REFERRAL \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::REFERRAL)
#define NS_ERROR_LDAP_ADMINLIMIT_EXCEEDED \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::ADMINLIMIT_EXCEEDED)
#define NS_ERROR_LDAP_UNAVAILABLE_CRITICAL_EXTENSION \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::UNAVAILABLE_CRITICAL_EXTENSION)
#define NS_ERROR_LDAP_CONFIDENTIALITY_REQUIRED \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::CONFIDENTIALITY_REQUIRED)
#define NS_ERROR_LDAP_SASL_BIND_IN_PROGRESS \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::SASL_BIND_IN_PROGRESS)
#define NS_ERROR_LDAP_NO_SUCH_ATTRIBUTE \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::NO_SUCH_ATTRIBUTE)
#define NS_ERROR_LDAP_UNDEFINED_TYPE \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::UNDEFINED_TYPE)
#define NS_ERROR_LDAP_INAPPROPRIATE_MATCHING \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::INAPPROPRIATE_MATCHING)
#define NS_ERROR_LDAP_CONSTRAINT_VIOLATION \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::CONSTRAINT_VIOLATION)
#define NS_ERROR_LDAP_TYPE_OR_VALUE_EXISTS \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::TYPE_OR_VALUE_EXISTS)
#define NS_ERROR_LDAP_INVALID_SYNTAX \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::INVALID_SYNTAX)
#define NS_ERROR_LDAP_NO_SUCH_OBJECT \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::NO_SUCH_OBJECT)
#define NS_ERROR_LDAP_ALIAS_PROBLEM \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::ALIAS_PROBLEM)
#define NS_ERROR_LDAP_INVALID_DN_SYNTAX \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::INVALID_DN_SYNTAX)
#define NS_ERROR_LDAP_IS_LEAF \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::IS_LEAF)
#define NS_ERROR_LDAP_ALIAS_DEREF_PROBLEM \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::ALIAS_DEREF_PROBLEM)
#define NS_ERROR_LDAP_INAPPROPRIATE_AUTH \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::INAPPROPRIATE_AUTH)
#define NS_ERROR_LDAP_INVALID_CREDENTIALS \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::INVALID_CREDENTIALS)
#define NS_ERROR_LDAP_INSUFFICIENT_ACCESS \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::INSUFFICIENT_ACCESS)
#define NS_ERROR_LDAP_BUSY \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::BUSY)
#define NS_ERROR_LDAP_UNAVAILABLE \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::UNAVAILABLE)
#define NS_ERROR_LDAP_UNWILLING_TO_PERFORM \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::UNWILLING_TO_PERFORM)
#define NS_ERROR_LDAP_LOOP_DETECT \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::LOOP_DETECT)
#define NS_ERROR_LDAP_SORT_CONTROL_MISSING \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::SORT_CONTROL_MISSING)
#define NS_ERROR_LDAP_INDEX_RANGE_ERROR \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::INDEX_RANGE_ERROR)
#define NS_ERROR_LDAP_NAMING_VIOLATION \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::NAMING_VIOLATION)
#define NS_ERROR_LDAP_OBJECT_CLASS_VIOLATION \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::OBJECT_CLASS_VIOLATION)
#define NS_ERROR_LDAP_NOT_ALLOWED_ON_NONLEAF \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::NOT_ALLOWED_ON_NONLEAF)
#define NS_ERROR_LDAP_NOT_ALLOWED_ON_RDN \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::NOT_ALLOWED_ON_RDN)
#define NS_ERROR_LDAP_ALREADY_EXISTS \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::ALREADY_EXISTS)
#define NS_ERROR_LDAP_NO_OBJECT_CLASS_MODS \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::NO_OBJECT_CLASS_MODS)
#define NS_ERROR_LDAP_RESULTS_TOO_LARGE \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::RESULTS_TOO_LARGE)
#define NS_ERROR_LDAP_AFFECTS_MULTIPLE_DSAS \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::AFFECTS_MULTIPLE_DSAS)
#define NS_ERROR_LDAP_OTHER \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::OTHER)
#define NS_ERROR_LDAP_SERVER_DOWN \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::SERVER_DOWN)
#define NS_ERROR_LDAP_LOCAL_ERROR \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::LOCAL_ERROR)
#define NS_ERROR_LDAP_ENCODING_ERROR \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::ENCODING_ERROR)
#define NS_ERROR_LDAP_DECODING_ERROR \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::DECODING_ERROR)
#define NS_ERROR_LDAP_TIMEOUT \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::TIMEOUT)
#define NS_ERROR_LDAP_AUTH_UNKNOWN \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::AUTH_UNKNOWN)
#define NS_ERROR_LDAP_FILTER_ERROR \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::FILTER_ERROR)
#define NS_ERROR_LDAP_USER_CANCELLED \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::USER_CANCELLED)
#define NS_ERROR_LDAP_PARAM_ERROR \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::PARAM_ERROR)
#define NS_ERROR_LDAP_NO_MEMORY \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::NO_MEMORY)
#define NS_ERROR_LDAP_CONNECT_ERROR \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::CONNECT_ERROR)
#define NS_ERROR_LDAP_NOT_SUPPORTED \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::NOT_SUPPORTED)
#define NS_ERROR_LDAP_CONTROL_NOT_FOUND \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::CONTROL_NOT_FOUND)
#define NS_ERROR_LDAP_NO_RESULTS_RETURNED \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::NO_RESULTS_RETURNED)
#define NS_ERROR_LDAP_MORE_RESULTS_TO_RETURN \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::MORE_RESULTS_TO_RETURN)
#define NS_ERROR_LDAP_CLIENT_LOOP \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::CLIENT_LOOP)
#define NS_ERROR_LDAP_REFERRAL_LIMIT_EXCEEDED \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, \
nsILDAPErrors::REFERRAL_LIMIT_EXCEEDED)
%}

View file

@ -0,0 +1,170 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
interface nsILDAPBERValue;
interface nsILDAPOperation;
%{C++
#define NS_LDAPMESSAGE_CONTRACTID "@mozilla.org/network/ldap-message;1"
%}
[scriptable, uuid(973ff50f-2002-4f0c-b57d-2242156139a2)]
interface nsILDAPMessage : nsISupports
{
/**
* The Distinguished Name of the entry associated with this message.
*
* @exception NS_ERROR_OUT_OF_MEMORY ran out of memory
* @exception NS_ERROR_ILLEGAL_VALUE null pointer passed in
* @exception NS_ERROR_LDAP_DECODING_ERROR problem during BER-decoding
* @exception NS_ERROR_UNEXPECTED bug or memory corruption
*/
readonly attribute AUTF8String dn;
/**
* Get all the attributes in this message.
*
* @exception NS_ERROR_OUT_OF_MEMORY
* @exception NS_ERROR_ILLEGAL_VALUE null pointer passed in
* @exception NS_ERROR_UNEXPECTED bug or memory corruption
* @exception NS_ERROR_LDAP_DECODING_ERROR problem during BER decoding
*
* @return array of all attributes in the current message
*/
void getAttributes(out unsigned long count,
[retval, array, size_is(count)] out string aAttributes);
/**
* Get an array of all the attribute values in this message.
*
* @param attr The attribute whose values are to be returned
* @param count Number of values in the outbound array.
* @param values Array of values
*
* @exception NS_ERROR_UNEXPECTED Bug or memory corruption
* @exception NS_ERROR_LDAP_DECODING_ERROR Attribute not found or other
* decoding error.
* @exception NS_ERROR_OUT_OF_MEMORY
*/
void getValues(in string attr, out unsigned long count,
[retval, array, size_is(count)] out wstring values);
/**
* The operation this message originated from
*
* @exception NS_ERROR_NULL_POINTER NULL pointer to getter
*/
readonly attribute nsILDAPOperation operation;
/**
* The result code (aka lderrno) for this message.
*
* IDL definitions for these constants live in nsILDAPErrors.idl.
*
* @exception NS_ERROR_ILLEGAL_VALUE null pointer passed in
*/
readonly attribute long errorCode;
/**
* The result type of this message. Possible types listed below, the
* values chosen are taken from the draft-ietf-ldapext-ldap-c-api-04.txt
* and are the same ones used in the ldap.h include file from the Mozilla
* LDAP C SDK.
*
* @exception NS_ERROR_ILLEGAL_VALUE null pointer passed in
* @exception NS_ERROR_UNEXPECTED internal error (possible memory
* corruption)
*/
readonly attribute long type;
/**
* Result of a bind operation
*/
const long RES_BIND = 0x61;
/**
* An entry found in an search operation.
*/
const long RES_SEARCH_ENTRY = 0x64;
/**
* An LDAPv3 search reference (a referral to another server)
*/
const long RES_SEARCH_REFERENCE = 0x73;
/**
* The result of a search operation (i.e. the search is done; no more
* entries to follow).
*/
const long RES_SEARCH_RESULT = 0x65;
/**
* The result of a modify operation.
*/
const long RES_MODIFY = 0x67;
/**
* The result of an add operation
*/
const long RES_ADD = 0x69;
/**
* The result of a delete operation
*/
const long RES_DELETE = 0x6B;
/**
* The result of an modify DN operation
*/
const long RES_MODDN = 0x6D;
/**
* The result of a compare operation
*/
const long RES_COMPARE = 0x6F;
/**
* The result of an LDAPv3 extended operation
*/
const long RES_EXTENDED = 0x78;
/**
* get an LDIF-like string representation of this message
*
* @return unicode encoded string representation.
*/
wstring toUnicode();
/**
* Additional error information optionally sent by the server.
*/
readonly attribute AUTF8String errorMessage;
/**
* In LDAPv3, when the server returns any of the following errors:
* NO_SUCH_OBJECT, ALIAS_PROBLEM, INVALID_DN_SYNTAX, ALIAS_DEREF_PROBLEM,
* it also returns the closest existing DN to the entry requested.
*/
readonly attribute AUTF8String matchedDn;
/**
* Get an array of all the attribute values in this message (a wrapper
* around the LDAP C SDK's get_values_len()).
*
* @param attr The attribute whose values are to be returned
* @param count Number of values in the outbound array.
* @param values Array of nsILDAPBERValue objects
*
* @exception NS_ERROR_UNEXPECTED Bug or memory corruption
* @exception NS_ERROR_LDAP_DECODING_ERROR Attribute not found or other
* decoding error.
* @exception NS_ERROR_OUT_OF_MEMORY
*/
void getBinaryValues(in string attr, out unsigned long count,
[retval, array, size_is(count)] out nsILDAPBERValue values);
};

View file

@ -0,0 +1,40 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
interface nsILDAPMessage;
interface nsILDAPConnection;
/**
* A callback interface to be implemented by any objects that want to
* receive results from an nsILDAPOperation (ie nsILDAPMessages) as they
* come in.
*/
[scriptable, uuid(dc721d4b-3ff2-4387-a80c-5e29545f774a)]
interface nsILDAPMessageListener : nsISupports
{
/**
* Messages received are passed back via this function.
*
* @arg aMessage The message that was returned, NULL if none was.
*
* XXX semantics of NULL?
*/
void onLDAPMessage(in nsILDAPMessage aMessage);
/**
* Notify the listener that the Init has completed, passing
* in the results from the connection initialization. The
* Reason for this is to allow us to do asynchronous DNS
* lookups, preresolving hostnames.
*
* @arg aConn The LDAP connection in question
* @arg aStatus The result from the LDAP connection init
*/
void onLDAPInit(in nsILDAPConnection aConn, in nsresult aStatus);
};

View file

@ -0,0 +1,58 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
interface nsILDAPBERValue;
interface nsIArray;
[scriptable, uuid(f64ef501-0623-11d6-a7f2-b65476fc49dc)]
interface nsILDAPModification : nsISupports
{
/**
* The operation to perform.
*/
attribute long operation;
/**
* Add operation
*/
const long MOD_ADD = 0x00;
/**
* Delete operation
*/
const long MOD_DELETE = 0x01;
/**
* Replace operation
*/
const long MOD_REPLACE = 0x02;
/**
* Values are BER encoded
*/
const long MOD_BVALUES = 0x80;
/**
* The attribute to modify.
*/
attribute ACString type;
/**
* The array of values this modification sets for the attribute
*/
attribute nsIArray values;
/**
* Function that allows all the attributes to be set at the same
* time to avoid multiple function calls.
*/
void setUpModification(in long aOperation, in ACString aType,
in nsIArray aValues);
void setUpModificationOneValue(in long aOperation, in ACString aType,
in nsILDAPBERValue aValue);
};

View file

@ -0,0 +1,275 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
#include "nsILDAPConnection.idl"
#include "nsIAuthModule.idl"
interface nsILDAPMessage;
interface nsILDAPMessageListener;
interface nsILDAPModification;
interface nsIMutableArray;
interface nsIArray;
%{C++
#define NS_LDAPOPERATION_CONTRACTID "@mozilla.org/network/ldap-operation;1"
%}
// XXXdmose check to make sure ctl-related err codes documented
typedef uint32_t PRIntervalTime;
[scriptable, uuid(4dfb1b19-fc8f-4525-92e7-f97b78a9747a)]
interface nsILDAPOperation : nsISupports
{
/**
* The connection this operation is on.
*
* @exception NS_ERROR_ILLEGAL_VALUE a NULL pointer was passed in
*/
readonly attribute nsILDAPConnection connection;
/**
* Callback for individual result messages related to this operation (set
* by the init() method). This is actually an nsISupports proxy object,
* as the callback will happen from another thread.
*
* @exception NS_ERROR_ILLEGAL_VALUE a NULL pointer was passed in
*/
readonly attribute nsILDAPMessageListener messageListener;
/**
* The message-id associated with this operation.
*
* @exception NS_ERROR_ILLEGAL_VALUE a NULL pointer was passed in
*/
readonly attribute long messageID;
/**
* private parameter (anything caller desires)
*/
attribute nsISupports closure;
/**
* No time and/or size limit specified
*/
const long NO_LIMIT = 0;
/**
* If specified, these arrays of nsILDAPControls are passed into the LDAP
* C SDK for any extended operations (ie method calls on this interface
* ending in "Ext").
*/
attribute nsIMutableArray serverControls;
attribute nsIMutableArray clientControls;
/**
* Initializes this operation. Must be called prior to initiating
* any actual operations. Note that by default, the aMessageListener
* callbacks happen on the LDAP connection thread. If you need them
* to happen on the main thread (or any other thread), then you should
* created an nsISupports proxy object and pass that in.
*
* @param aConnection connection this operation should use
* @param aMessageListener interface used to call back the results.
* @param aClosure private parameter (anything caller desires)
*
* @exception NS_ERROR_ILLEGAL_VALUE a NULL pointer was passed in
* @exception NS_ERROR_UNEXPECTED failed to get connection handle
*/
void init(in nsILDAPConnection aConnection,
in nsILDAPMessageListener aMessageListener,
in nsISupports aClosure);
/**
* Asynchronously authenticate to the LDAP server.
*
* @param passwd the password used for binding; NULL for anon-binds
*
* @exception NS_ERROR_LDAP_ENCODING_ERROR problem encoding bind request
* @exception NS_ERROR_LDAP_SERVER_DOWN server down (XXX rebinds?)
* @exception NS_ERROR_LDAP_CONNECT_ERROR connection failed or lost
* @exception NS_ERROR_OUT_OF_MEMORY ran out of memory
* @exception NS_ERROR_UNEXPECTED internal error
*/
void simpleBind(in AUTF8String passwd);
/**
* Asynchronously perform a SASL bind against the LDAP server
*
* @param service the host name of the service being connected to
* @param mechanism the name of the SASL mechanism in use
* @param authModule the nsIAuthModule to be used to perform the operation
*
*/
void saslBind(in ACString service, in ACString mechanism,
in nsIAuthModule authModule);
/**
* Continue a SASL bind operation
*
* @param token the next SASL token to send to the server
* @param tokenLen the length of the token to send
*
*/
void saslStep(in string token, in unsigned long tokenLen);
/**
* Kicks off an asynchronous add request. The "ext" stands for
* "extensions", and is intended to convey that this method will
* eventually support the extensions described in the
* draft-ietf-ldapext-ldap-c-api-04.txt Internet Draft.
*
* @param aBaseDn Base DN to add
* @param aModCount Number of modifications
* @param aMods Array of modifications
*
* @exception NS_ERROR_NOT_INITIALIZED operation not initialized
* @exception NS_ERROR_INVALID_ARG invalid argument
* @exception NS_ERROR_LDAP_ENCODING_ERROR error during BER-encoding
* @exception NS_ERROR_LDAP_SERVER_DOWN the LDAP server did not
* receive the request or the
* connection was lost
* @exception NS_ERROR_OUT_OF_MEMORY ran out of memory
* @exception NS_ERROR_LDAP_NOT_SUPPORTED not supported in the version
* of the LDAP protocol that the
* client is using
* @exception NS_ERROR_UNEXPECTED an unexpected error has
* occurred
*
* XXX doesn't currently handle LDAPControl params
*/
void addExt(in AUTF8String aBaseDn, in nsIArray aMods);
/**
* Kicks off an asynchronous delete request. The "ext" stands for
* "extensions", and is intended to convey that this method will
* eventually support the extensions described in the
* draft-ietf-ldapext-ldap-c-api-04.txt Internet Draft.
*
* @param aBaseDn Base DN to delete
*
* @exception NS_ERROR_NOT_INITIALIZED operation not initialized
* @exception NS_ERROR_INVALID_ARG invalid argument
* @exception NS_ERROR_LDAP_ENCODING_ERROR error during BER-encoding
* @exception NS_ERROR_LDAP_SERVER_DOWN the LDAP server did not
* receive the request or the
* connection was lost
* @exception NS_ERROR_OUT_OF_MEMORY ran out of memory
* @exception NS_ERROR_LDAP_NOT_SUPPORTED not supported in the version
* of the LDAP protocol that the
* client is using
* @exception NS_ERROR_UNEXPECTED an unexpected error has
* occurred
*
* XXX doesn't currently handle LDAPControl params
*/
void deleteExt(in AUTF8String aBaseDn);
/**
* Kicks off an asynchronous modify request. The "ext" stands for
* "extensions", and is intended to convey that this method will
* eventually support the extensions described in the
* draft-ietf-ldapext-ldap-c-api-04.txt Internet Draft.
*
* @param aBaseDn Base DN to modify
* @param aModCount Number of modifications
* @param aMods Array of modifications
*
* @exception NS_ERROR_NOT_INITIALIZED operation not initialized
* @exception NS_ERROR_INVALID_ARG invalid argument
* @exception NS_ERROR_LDAP_ENCODING_ERROR error during BER-encoding
* @exception NS_ERROR_LDAP_SERVER_DOWN the LDAP server did not
* receive the request or the
* connection was lost
* @exception NS_ERROR_OUT_OF_MEMORY ran out of memory
* @exception NS_ERROR_LDAP_NOT_SUPPORTED not supported in the version
* of the LDAP protocol that the
* client is using
* @exception NS_ERROR_UNEXPECTED an unexpected error has
* occurred
*
* XXX doesn't currently handle LDAPControl params
*/
void modifyExt(in AUTF8String aBaseDn, in nsIArray aMods);
/**
* Kicks off an asynchronous rename request.
*
* @param aBaseDn Base DN to rename
* @param aNewRDn New relative DN
* @param aNewParent DN of the new parent under which to move the
* entry
* @param aDeleteOldRDn Indicates whether to remove the old relative
* DN as a value in the entry or not
*
* @exception NS_ERROR_NOT_INITIALIZED operation not initialized
* @exception NS_ERROR_INVALID_ARG invalid argument
* @exception NS_ERROR_LDAP_ENCODING_ERROR error during BER-encoding
* @exception NS_ERROR_LDAP_SERVER_DOWN the LDAP server did not
* receive the request or the
* connection was lost
* @exception NS_ERROR_OUT_OF_MEMORY ran out of memory
* @exception NS_ERROR_LDAP_NOT_SUPPORTED not supported in the version
* of the LDAP protocol that the
* client is using
* @exception NS_ERROR_UNEXPECTED an unexpected error has
* occurred
*
* XXX doesn't currently handle LDAPControl params
*/
void rename(in AUTF8String aBaseDn, in AUTF8String aNewRDn,
in AUTF8String aNewParent, in boolean aDeleteOldRDn);
/**
* Kicks off an asynchronous search request. The "ext" stands for
* "extensions", and is intended to convey that this method will
* eventually support the extensions described in the
* draft-ietf-ldapext-ldap-c-api-04.txt Internet Draft.
*
* @param aBaseDn Base DN to search
* @param aScope One of SCOPE_{BASE,ONELEVEL,SUBTREE}
* @param aFilter Search filter
* @param aAttributes Comma separated list of values, holding the
* attributes we need
* @param aTimeOut How long to wait
* @param aSizeLimit Maximum number of entries to return.
*
* @exception NS_ERROR_NOT_INITIALIZED operation not initialized
* @exception NS_ERROR_LDAP_ENCODING_ERROR error during BER-encoding
* @exception NS_ERROR_LDAP_SERVER_DOWN the LDAP server did not
* receive the request or the
* connection was lost
* @exception NS_ERROR_OUT_OF_MEMORY ran out of memory
* @exception NS_ERROR_INVALID_ARG invalid argument
* @exception NS_ERROR_LDAP_NOT_SUPPORTED not supported in the version
* of the LDAP protocol that the
* client is using
* @exception NS_ERROR_LDAP_FILTER_ERROR
* @exception NS_ERROR_UNEXPECTED
*/
void searchExt(in AUTF8String aBaseDn, in int32_t aScope,
in AUTF8String aFilter, in ACString aAttributes,
in PRIntervalTime aTimeOut, in int32_t aSizeLimit);
/**
* Cancels an async operation that is in progress.
*
* XXX controls not supported yet
*
* @exception NS_ERROR_NOT_IMPLEMENTED server or client controls
* were set on this object
* @exception NS_ERROR_NOT_INITIALIZED operation not initialized
* @exception NS_ERROR_LDAP_ENCODING_ERROR error during BER-encoding
* @exception NS_ERROR_LDAP_SERVER_DOWN the LDAP server did not
* receive the request or the
* connection was lost
* @exception NS_ERROR_OUT_OF_MEMORY out of memory
* @exception NS_ERROR_INVALID_ARG invalid argument
* @exception NS_ERROR_UNEXPECTED internal error
*/
void abandonExt();
};

View file

@ -0,0 +1,86 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
#include "nsILDAPConnection.idl"
interface nsILDAPURL;
/**
* this interface provides a way to store, retrieve and manipulate
* information related to a specific LDAP server. This includes the
* LDAP URL, as well as certain user specific data (e.g. credentials).
*
* The implementation of nsILDAPService relies heavily on this
* interface, managing all LDAP connections (nsILDAPConnection).
* The Service manages LDAP connections (connect and disconnect etc.),
* using the information available from these LDAP Server objects.
*/
[scriptable, uuid(8aa717a4-1dd2-11b2-99c7-f01e2d449ded)]
interface nsILDAPServer : nsISupports {
/**
* unique identifier for this server, used (typically) to identify a
* particular server object in a list of servers. This key can be
* any "string", but in our case it will most likely be the same
* identifier as used in a Mozilla preferences files.
*
* @exception NS_ERROR_NULL_POINTER NULL pointer to GET method
* @exception NS_ERROR_OUT_OF_MEMORY ran out of memory
*/
attribute wstring key;
/**
* the password string used to bind to this server. An empty
* string here implies binding as anonymous.
*
* @exception NS_ERROR_NULL_POINTER NULL pointer to GET method
* @exception NS_ERROR_OUT_OF_MEMORY ran out of memory
*/
attribute AUTF8String password;
/**
* the user name to authenticate as. An empty string here would
* imply binding as anonymous.
*
* @exception NS_ERROR_NULL_POINTER NULL pointer to GET method
* @exception NS_ERROR_OUT_OF_MEMORY ran out of memory
*/
attribute AUTF8String username;
/**
* the bind DN (Distinguished Name).
*
* @exception NS_ERROR_NULL_POINTER NULL pointer to GET method
* @exception NS_ERROR_OUT_OF_MEMORY ran out of memory
*/
attribute AUTF8String binddn;
/** maximum number of hits we want to accept from an LDAP search
* operation.
*
* @exception NS_ERROR_NULL_POINTER NULL pointer to GET method
*/
attribute unsigned long sizelimit;
/**
* the URL for this server.
*
* @exception NS_ERROR_NULL_POINTER NULL pointer to GET method
*/
attribute nsILDAPURL url;
/**
* protocol version to be used (see nsILDAPConnection.idl for constants)
* Defaults to 3.
*
* @exception NS_ERROR_NULL_POINTER NULL pointer passed to getter
* @exception NS_ERROR_INVALID_ARG Invalid version passed to setter
*/
attribute unsigned long protocolVersion;
};

View file

@ -0,0 +1,197 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
interface nsILDAPServer;
interface nsILDAPConnection;
interface nsILDAPMessageListener;
/**
* This interface provides an LDAP connection management service.
* It's used to cache already established LDAP connections, as well
* as reaping unused connections after a certain time period. This
* is done completely asynchronously, using callback functions.
*/
[scriptable, uuid(69de6fbc-2e8c-4482-bf14-358d68b785d1)]
interface nsILDAPService : nsISupports {
/**
* Add a (possibly) new LDAP server entry to the service. A
* server entry holds information about the host, port and
* other components of the LDAP URL, as well as information
* used for binding a connection to the LDAP server.
*
* An LDAP Server entry (nsILDAPServer) contains the URL,
* user credentials, and other information related to the actual
* server itself. It is used for connecting, binding, rebinding,
* setting timeouts and so forth.
*
* @param aServer an nsILDAPServer object
*
* @exception NS_ERROR_FAILURE the server has already been
* added to the service
* @exception NS_ERROR_NULL_POINTER NULL pointer
* @exception NS_ERROR_OUT_OF_MEMORY ran out of memory
*/
void addServer(in nsILDAPServer aServer);
/**
* Mark an LDAP server, in the Service, as a candidate for
* deletion. If there are still leases ("users") of this server,
* the operation fails.
*
* @param aKey unique key identifying the server entry
*
* @exception NS_ERROR_FAILURE either the server doesn't
* exist, or there are still
* leases oustanding
*/
void deleteServer(in wstring aKey);
/**
* Get the nsILDAPServer object for the specified server entry
* in the service.
*
* @param aKey unique key identifying the server entry
*
* @exception NS_ERROR_FAILURE there is no server registered
* in the service with this key
* @exception NS_ERROR_NULL_POINTER NULL pointer
*/
nsILDAPServer getServer(in wstring aKey);
/**
* Request a connection from the service, asynchronously. If there is
* one "cached" already, we will actually call the callback function
* before returning from this function. This might be considered a bug,
* but for now be aware of this (see Bugzilla bug #75989).
*
* Calling this method does not increment the leases on this connection,
* you'll have to use the getConnection() method to actually get the
* connection itself (presumably from the callback/listener object).
* The listener needs to implement nsILDAPMessageListener, providing
* the OnLDAPMessage() method.
*
* @param aKey unique key identifying the server entry
* @param aMessageListener the listener object, which we will call
* when the LDAP bind message is available
*
* @exception NS_ERROR_FAILURE there is no server registered
* in the service with this key,
* or we were unable to get a
* connection properly to the server
* @exception NS_ERROR_NOT_AVAILABLE couldn't create connection thread
* @exception NS_ERROR_OUT_OF_MEMORY ran out of memory
* @exception NS_ERROR_UNEXPECTED unknown or unexpected error...
*/
void requestConnection(in wstring aKey,
in nsILDAPMessageListener aListener);
/**
* This is the nsLDAPConnection object related to this server.
* This does increase the lease counter on the object, so you have
* to call the releaseConnection() method to return it. It is
* important that you do this in matching pairs, and that you do
* not keep any dangling references to an object around after you
* have called the releaseConnection() method.
*
* @param aKey unique key identifying the server entry
*
* @exception NS_ERROR_FAILURE there is no server registered
* in the service with this key
* @exception NS_ERROR_NULL_POINTER NULL pointer
*/
nsILDAPConnection getConnection(in wstring aKey);
/**
* Release the lease on a (cached) LDAP connection, making it a
* potential candidate for disconnection. Note that this will not
* delete the actual LDAP server entry in the service, it's still
* registered and can be used in future calls to requestConnection().
*
* This API might be deprecated in the future, once we figure out how
* to use weak references to support our special needs for reference
* counting. For the time being, it is vital that you call this function
* when you're done with a Connection, and that you do not keep any
* copies of the Connection object lingering around.
*
* @param aKey unique key identifying the server entry
*
* @exception NS_ERROR_FAILURE there is no server registered
* in the service with this key
* @exception NS_ERROR_OUT_OF_MEMORY ran out of memory
*/
void releaseConnection(in wstring aKey);
/**
* If we detect that a connection is broken (server disconnected us,
* or any other problem with the link), we need to try to reestablish
* the connection. This is very similar to requestConnection(),
* except you use this when detecting an error with a connection
* that is being cached.
*
* @param aKey unique key identifying the server entry
* @param aMessageListener the listener object, which we will call
* when the LDAP bind message is available
*
* @exception NS_ERROR_FAILURE there is no server registered
* in the service with this key,
* or we were unable to get a
* connection properly to the server
* @exception NS_ERROR_NOT_AVAILABLE couldn't create connection thread
* @exception NS_ERROR_OUT_OF_MEMORY ran out of memory
* @exception NS_ERROR_UNEXPECTED unknown or unexpected error...
*/
void reconnectConnection(in wstring aKey,
in nsILDAPMessageListener aListener);
/**
* Generates and returns an LDAP search filter by substituting
* aValue, aAttr, aPrefix, and aSuffix into aPattern.
*
* The only good documentation I'm aware of for this function is
* at <http://docs.iplanet.com/docs/manuals/dirsdk/csdk41/html/filter.htm>
* and
* <http://docs.iplanet.com/docs/manuals/dirsdk/csdk41/html/function.htm#17835>
* Unfortunately, this does not currently seem to be available
* under any open source license, so I can't include that
* documentation here in the doxygen comments.
*
* @param aMaxSize maximum size (in char) of string to be
* created and returned (including final \0)
* @param aPattern pattern to be used for the filter
* @param aPrefix prefix to prepend to the filter
* @param aSuffix suffix to be appended to the filer
* @param aAttr replacement for %a in the pattern
* @param aValue replacement for %v in the pattern
*
* @exception NS_ERROR_INVALID_ARG invalid parameter passed in
* @exception NS_ERROR_OUT_OF_MEMORY allocation failed
* @exception NS_ERROR_NOT_AVAILABLE filter longer than maxsiz chars
* @exception NS_ERROR_UNEXPECTED ldap_create_filter returned
* unexpected error code
*/
AUTF8String createFilter(in unsigned long aMaxSize, in AUTF8String aPattern,
in AUTF8String aPrefix, in AUTF8String aSuffix,
in AUTF8String aAttr, in AUTF8String aValue);
/**
* Parses a distinguished name (DN) and returns the relative DN,
* base DN and the list of attributes that make up the relative DN.
*
* @param dn DN to parse
* @param rdn The relative DN for the given DN
* @param baseDn The base DN for the given DN
* @param rdnCount Number of values in the outbound attributes array.
* @param rdnAttrs Array of attribute names
*
*/
void parseDn(in string dn, out AUTF8String rdn, out AUTF8String baseDn,
out unsigned long rdnCount,
[retval, array, size_is(rdnCount)] out string rdnAttrs);
};

View file

@ -0,0 +1,27 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
interface nsILDAPURL;
[scriptable, uuid (0308fb36-1dd2-11b2-b16f-8510e8c5311a)]
interface nsILDAPSyncQuery : nsISupports {
/**
* getQueryResults
*
* Create a new LDAP connection do a synchronous LDAP search and return
* the results.
* @param aServerURL - LDAP URL with parameters to a LDAP search
* ("ldap://host/base?attributes?one/sub?filter")
* @param aProtocolVersion - LDAP protocol version to use for connection
* (nsILDAPConnection.idl has symbolic constants)
* @return results
*/
wstring getQueryResults (in nsILDAPURL aServerURL,
in unsigned long aProtocolVersion);
};

View file

@ -0,0 +1,132 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsIURI.idl"
%{C++
#define NS_LDAPURL_CONTRACTID "@mozilla.org/network/ldap-url;1"
%}
/**
* Strings in methods inherited from nsIURI, which are using XPIDL
* |string| types, are expected to be UTF8 encoded. All such strings
* in this interface, except attribute types (e.g. "cn"), should in fact
* be UTF8. It's important to remember that attributes can not be UTF8,
* they can only be of a limited subset of ASCII (see RFC 2251).
*/
[scriptable, uuid(8e3a6d33-2e68-40ba-8f94-6ac03f69066e)]
interface nsILDAPURL : nsIURI {
/**
* Initialize an LDAP URL
*
* @param aUrlType - one of the URLTYPE_ flags @seealso nsIStandardURL
* @param aDefaultPort - if the port parsed from the URL string matches
* this port, then the port will be removed from the
* canonical form of the URL.
* @param aSpec - URL string.
* @param aOriginCharset - the charset from which this URI string
* originated. this corresponds to the charset
* that should be used when communicating this
* URI to an origin server, for example. if
* null, then provide aBaseURI implements this
* interface, the origin charset of aBaseURI will
* be assumed, otherwise defaulting to UTF-8 (i.e.,
* no charset transformation from aSpec).
* @param aBaseURI - if null, aSpec must specify an absolute URI.
* otherwise, aSpec will be resolved relative
* to aBaseURI.
*/
void init(in unsigned long aUrlType,
in long aDefaultPort,
in AUTF8String aSpec,
in string aOriginCharset,
in nsIURI aBaseURI);
/**
* The distinguished name of the URL (ie the base DN for the search).
* This string is expected to be a valid UTF8 string.
*
* for the getter:
*
* @exception NS_ERROR_NULL_POINTER NULL pointer to GET method
* @exception NS_ERROR_OUT_OF_MEMORY Ran out of memory
*/
attribute AUTF8String dn;
/**
* The attributes to get for this URL, in comma-separated format. If the
* list is empty, all attributes are requested.
*/
attribute ACString attributes;
/**
* Add one attribute to the array of attributes to request. If the
* attribute is already in our array, this becomes a noop.
*
* @param aAttribute An LDAP attribute (e.g. "cn")
*/
void addAttribute(in ACString aAttribute);
/**
* Remove one attribute from the array of attributes to request. If
* the attribute didn't exist in the array, this becomes a noop.
*
* @param aAttribute An LDAP attribute (e.g. "cn")
* @exception NS_ERROR_OUT_OF_MEMORY Ran out of memory
*/
void removeAttribute(in ACString aAttribute);
/**
* Test if an attribute is in our list of attributes already
*
* @param aAttribute An LDAP attribute (e.g. "cn")
* @return boolean Truth value
* @exception NS_ERROR_NULL_POINTER NULL pointer to GET method
*/
boolean hasAttribute(in ACString aAttribute);
/**
* The scope of the search. defaults to SCOPE_BASE.
*
* @exception NS_ERROR_NULL_POINTER NULL pointer to GET method
* @exception NS_ERROR_MALFORMED_URI Illegal base to SET method
*/
attribute long scope;
/**
* Search just the base object
*/
const long SCOPE_BASE = 0;
/**
* Search only the children of the base object
*/
const long SCOPE_ONELEVEL = 1;
/**
* Search the entire subtree under and including the base object
*/
const long SCOPE_SUBTREE = 2;
/**
* The search filter. "(objectClass=*)" is the default.
*/
attribute AUTF8String filter;
/**
* Any options defined for this URL (check options using a bitwise and)
*
* @exception NS_ERROR_NULL_POINTER NULL pointer to GET method
* @exception NS_ERROR_OUT_OF_MEMORY Ran out of memory
*/
attribute unsigned long options;
/**
* If this is set/true, this is an ldaps: URL, not an ldap: URL
*/
const unsigned long OPT_SECURE = 0x01;
};

View file

@ -0,0 +1,5 @@
component {b3de9249-b0e5-4c12-8d91-c9a434fd80f5} nsLDAPProtocolHandler.js
contract @mozilla.org/network/protocol;1?name=ldap {b3de9249-b0e5-4c12-8d91-c9a434fd80f5}
component {c85a5ef2-9c56-445f-b029-76889f2dd29b} nsLDAPProtocolHandler.js
contract @mozilla.org/network/protocol;1?name=ldaps {c85a5ef2-9c56-445f-b029-76889f2dd29b}

53
ldap/xpcom/src/moz.build Normal file
View file

@ -0,0 +1,53 @@
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
SOURCES += [
'nsLDAPBERElement.cpp',
'nsLDAPBERValue.cpp',
'nsLDAPConnection.cpp',
'nsLDAPControl.cpp',
'nsLDAPMessage.cpp',
'nsLDAPModification.cpp',
'nsLDAPOperation.cpp',
'nsLDAPProtocolModule.cpp',
'nsLDAPSecurityGlue.cpp',
'nsLDAPServer.cpp',
'nsLDAPService.cpp',
'nsLDAPURL.cpp',
]
if CONFIG['MOZ_PREF_EXTENSIONS']:
SOURCES += ['nsLDAPSyncQuery.cpp']
DEFINES['MOZ_PREF_EXTENSIONS'] = True
EXTRA_COMPONENTS += [
'ldapComponents.manifest',
'nsLDAPProtocolHandler.js',
]
USE_LIBS += [
'ldapsdks',
]
if CONFIG['MOZ_INCOMPLETE_EXTERNAL_LINKAGE']:
XPCOMBinaryComponent('mozldap')
USE_LIBS += [
'nspr',
'xpcomglue_s',
'xul',
]
# js needs to come after xul for now, because it is an archive and its content
# is discarded when it comes first.
USE_LIBS += [
'js',
]
else:
Library('mozldap')
FINAL_LIBRARY = 'xul'
LOCAL_INCLUDES += [
'/ldap/c-sdk/include',
]

View file

@ -0,0 +1,117 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsLDAPBERElement.h"
#include "nsStringGlue.h"
#include "nsCOMPtr.h"
#include "nsLDAPBERValue.h"
NS_IMPL_ISUPPORTS(nsLDAPBERElement, nsILDAPBERElement)
nsLDAPBERElement::nsLDAPBERElement()
: mElement(0)
{
}
nsLDAPBERElement::~nsLDAPBERElement()
{
if (mElement) {
// anything inside here is not something that we own separately from
// this object, so free it
ber_free(mElement, 1);
}
return;
}
NS_IMETHODIMP
nsLDAPBERElement::Init(nsILDAPBERValue *aValue)
{
if (aValue) {
return NS_ERROR_NOT_IMPLEMENTED;
}
mElement = ber_alloc_t(LBER_USE_DER);
return mElement ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
}
/* void putString (in AUTF8String aString, in unsigned long aTag); */
NS_IMETHODIMP
nsLDAPBERElement::PutString(const nsACString & aString, uint32_t aTag,
uint32_t *aBytesWritten)
{
// XXX if the string translation feature of the C SDK is ever used,
// this const_cast will break
int i = ber_put_ostring(mElement,
const_cast<char *>(PromiseFlatCString(aString).get()),
aString.Length(), aTag);
if (i < 0) {
return NS_ERROR_FAILURE;
}
*aBytesWritten = i;
return NS_OK;
}
/* void startSet (); */
NS_IMETHODIMP nsLDAPBERElement::StartSet(uint32_t aTag)
{
int i = ber_start_set(mElement, aTag);
if (i < 0) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
/* void putSet (); */
NS_IMETHODIMP nsLDAPBERElement::PutSet(uint32_t *aBytesWritten)
{
int i = ber_put_set(mElement);
if (i < 0) {
return NS_ERROR_FAILURE;
}
*aBytesWritten = i;
return NS_OK;
}
/* nsILDAPBERValue flatten (); */
NS_IMETHODIMP nsLDAPBERElement::GetAsValue(nsILDAPBERValue **_retval)
{
// create the value object
nsCOMPtr<nsILDAPBERValue> berValue = new nsLDAPBERValue();
if (!berValue) {
NS_ERROR("nsLDAPBERElement::GetAsValue(): out of memory"
" creating nsLDAPBERValue object");
return NS_ERROR_OUT_OF_MEMORY;
}
struct berval *bv;
if ( ber_flatten(mElement, &bv) < 0 ) {
return NS_ERROR_OUT_OF_MEMORY;
}
nsresult rv = berValue->Set(bv->bv_len,
reinterpret_cast<uint8_t *>(bv->bv_val));
// whether or not we've succeeded, we're done with the ldap c sdk struct
ber_bvfree(bv);
// as of this writing, this error can only be NS_ERROR_OUT_OF_MEMORY
if (NS_FAILED(rv)) {
return rv;
}
// return the raw interface pointer
NS_ADDREF(*_retval = berValue.get());
return NS_OK;
}

View file

@ -0,0 +1,30 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "lber.h"
#include "nsILDAPBERElement.h"
// 070af769-b7f5-40e7-81be-196155ead84c
#define NS_LDAPBERELEMENT_CID \
{ 0x070af769, 0xb7f5, 0x40e7, \
{ 0x81, 0xbe, 0x19, 0x61, 0x55, 0xea, 0xd8, 0x4c }}
class nsLDAPBERElement final : public nsILDAPBERElement
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSILDAPBERELEMENT
nsLDAPBERElement();
private:
~nsLDAPBERElement();
BerElement *mElement;
protected:
};

View file

@ -0,0 +1,106 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsLDAPBERValue.h"
#include "nsMemory.h"
#include "nsStringGlue.h"
NS_IMPL_ISUPPORTS(nsLDAPBERValue, nsILDAPBERValue)
nsLDAPBERValue::nsLDAPBERValue() : mValue(0), mSize(0)
{
}
nsLDAPBERValue::~nsLDAPBERValue()
{
if (mValue) {
free(mValue);
}
}
// void get (out unsigned long aCount,
// [array, size_is (aCount), retval] out octet aRetVal); */
NS_IMETHODIMP
nsLDAPBERValue::Get(uint32_t *aCount, uint8_t **aRetVal)
{
// if mSize = 0, return a count of a 0 and a null pointer
if (mSize) {
// get a buffer to hold a copy of the data
//
uint8_t *array = static_cast<uint8_t *>(moz_xmalloc(mSize));
if (!array) {
return NS_ERROR_OUT_OF_MEMORY;
}
// copy and return
//
memcpy(array, mValue, mSize);
*aRetVal = array;
} else {
*aRetVal = 0;
}
*aCount = mSize;
return NS_OK;
}
// void set(in unsigned long aCount,
// [array, size_is(aCount)] in octet aValue);
NS_IMETHODIMP
nsLDAPBERValue::Set(uint32_t aCount, uint8_t *aValue)
{
// get rid of any old value being held here
//
if (mValue) {
free(mValue);
}
// if this is a non-zero value, allocate a buffer and copy
//
if (aCount) {
// get a buffer to hold a copy of this data
//
mValue = static_cast<uint8_t *>(moz_xmalloc(aCount));
if (!mValue) {
return NS_ERROR_OUT_OF_MEMORY;
}
// copy the data and return
//
memcpy(mValue, aValue, aCount);
} else {
// otherwise just set it to null
//
mValue = 0;
}
mSize = aCount;
return NS_OK;
}
// void setFromUTF8(in AUTF8String aValue);
//
NS_IMETHODIMP
nsLDAPBERValue::SetFromUTF8(const nsACString & aValue)
{
// get rid of any old value being held here
//
if (mValue) {
free(mValue);
}
// copy the data and return
//
mSize = aValue.Length();
if (mSize) {
mValue = reinterpret_cast<uint8_t *>(ToNewCString(aValue));
} else {
mValue = 0;
}
return NS_OK;
}

View file

@ -0,0 +1,40 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _nsLDAPBERValue_h_
#define _nsLDAPBERValue_h_
#include "ldap.h"
#include "nsILDAPBERValue.h"
// 7c9fa10e-1dd2-11b2-a097-ac379e6803b2
//
#define NS_LDAPBERVALUE_CID \
{ 0x7c9fa10e, 0x1dd2, 0x11b2, \
{0xa0, 0x97, 0xac, 0x37, 0x9e, 0x68, 0x03, 0xb2 }}
class nsLDAPBERValue : public nsILDAPBERValue
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSILDAPBERVALUE
nsLDAPBERValue();
protected:
virtual ~nsLDAPBERValue();
/**
* nsLDAPControl needs to be able to grovel through this without an
* an extra copy
*/
friend class nsLDAPControl;
uint8_t *mValue; // pointer to an array
uint32_t mSize; // size of the value, in bytes
};
#endif // _nsLDAPBERValue_h_

View file

@ -0,0 +1,737 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsLDAPInternal.h"
#include "nsIServiceManager.h"
#include "nsStringGlue.h"
#include "nsIComponentManager.h"
#include "nsIDNSRecord.h"
#include "nsLDAPConnection.h"
#include "nsLDAPMessage.h"
#include "nsThreadUtils.h"
#include "nsIConsoleService.h"
#include "nsIDNSService.h"
#include "nsINetAddr.h"
#include "nsIRequestObserver.h"
#include "nsError.h"
#include "nsLDAPOperation.h"
#include "nsILDAPErrors.h"
#include "nsIClassInfoImpl.h"
#include "nsILDAPURL.h"
#include "nsIObserverService.h"
#include "mozilla/Services.h"
#include "nsMemory.h"
#include "nsLDAPUtils.h"
#include "nsProxyRelease.h"
#include "mozilla/Logging.h"
#include "mozilla/Attributes.h"
using namespace mozilla;
const char kDNSServiceContractId[] = "@mozilla.org/network/dns-service;1";
// constructor
//
nsLDAPConnection::nsLDAPConnection()
: mConnectionHandle(nullptr),
mPendingOperationsMutex("nsLDAPConnection.mPendingOperationsMutex"),
mPendingOperations(10),
mSSL(false),
mVersion(nsILDAPConnection::VERSION3),
mDNSRequest(nullptr)
{
}
// destructor
//
nsLDAPConnection::~nsLDAPConnection()
{
nsCOMPtr<nsIObserverService> obsServ =
do_GetService(NS_OBSERVERSERVICE_CONTRACTID);
if (obsServ)
obsServ->RemoveObserver(this, "profile-change-net-teardown");
Close();
}
NS_IMPL_ADDREF(nsLDAPConnection)
NS_IMPL_RELEASE(nsLDAPConnection)
NS_IMPL_CLASSINFO(nsLDAPConnection, NULL, nsIClassInfo::THREADSAFE,
NS_LDAPCONNECTION_CID)
NS_INTERFACE_MAP_BEGIN(nsLDAPConnection)
NS_INTERFACE_MAP_ENTRY(nsILDAPConnection)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_INTERFACE_MAP_ENTRY(nsIDNSListener)
NS_INTERFACE_MAP_ENTRY(nsIObserver)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsILDAPConnection)
NS_IMPL_QUERY_CLASSINFO(nsLDAPConnection)
NS_INTERFACE_MAP_END_THREADSAFE
NS_IMPL_CI_INTERFACE_GETTER(nsLDAPConnection, nsILDAPConnection,
nsISupportsWeakReference, nsIDNSListener,
nsIObserver)
NS_IMETHODIMP
nsLDAPConnection::Init(nsILDAPURL *aUrl, const nsACString &aBindName,
nsILDAPMessageListener *aMessageListener,
nsISupports *aClosure, uint32_t aVersion)
{
NS_ENSURE_ARG_POINTER(aUrl);
NS_ENSURE_ARG_POINTER(aMessageListener);
nsresult rv;
nsCOMPtr<nsIObserverService> obsServ =
do_GetService(NS_OBSERVERSERVICE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
// We have to abort all LDAP pending operation before shutdown.
obsServ->AddObserver(this, "profile-change-net-teardown", true);
// Save various items that we'll use later
mBindName.Assign(aBindName);
mClosure = aClosure;
mInitListener = aMessageListener;
// Make sure we haven't called Init earlier, i.e. there's a DNS
// request pending.
NS_ASSERTION(!mDNSRequest, "nsLDAPConnection::Init() "
"Connection was already initialized\n");
// Check and save the version number
if (aVersion != nsILDAPConnection::VERSION2 &&
aVersion != nsILDAPConnection::VERSION3) {
NS_ERROR("nsLDAPConnection::Init(): illegal version");
return NS_ERROR_ILLEGAL_VALUE;
}
mVersion = aVersion;
// Get the port number, SSL flag for use later, once the DNS server(s)
// has resolved the host part.
rv = aUrl->GetPort(&mPort);
NS_ENSURE_SUCCESS(rv, rv);
uint32_t options;
rv = aUrl->GetOptions(&options);
NS_ENSURE_SUCCESS(rv, rv);
mSSL = options & nsILDAPURL::OPT_SECURE;
nsCOMPtr<nsIThread> curThread = do_GetCurrentThread();
if (!curThread) {
NS_ERROR("nsLDAPConnection::Init(): couldn't get current thread");
return NS_ERROR_FAILURE;
}
// Do the pre-resolve of the hostname, using the DNS service. This
// will also initialize the LDAP connection properly, once we have
// the IPs resolved for the hostname. This includes creating the
// new thread for this connection.
//
// XXX - What return codes can we expect from the DNS service?
//
nsCOMPtr<nsIDNSService>
pDNSService(do_GetService(kDNSServiceContractId, &rv));
if (NS_FAILED(rv)) {
NS_ERROR("nsLDAPConnection::Init(): couldn't create the DNS Service object");
return NS_ERROR_FAILURE;
}
rv = aUrl->GetAsciiHost(mDNSHost);
NS_ENSURE_SUCCESS(rv, rv);
// if the caller has passed in a space-delimited set of hosts, as the
// ldap c-sdk allows, strip off the trailing hosts for now.
// Soon, we'd like to make multiple hosts work, but now make
// at least the first one work.
LdapCompressWhitespace(mDNSHost);
int32_t spacePos = mDNSHost.FindChar(' ');
// trim off trailing host(s)
if (spacePos != kNotFound)
mDNSHost.SetLength(spacePos);
rv = pDNSService->AsyncResolve(mDNSHost, 0, this, curThread,
getter_AddRefs(mDNSRequest));
if (NS_FAILED(rv)) {
switch (rv) {
case NS_ERROR_OUT_OF_MEMORY:
case NS_ERROR_UNKNOWN_HOST:
case NS_ERROR_FAILURE:
case NS_ERROR_OFFLINE:
break;
default:
rv = NS_ERROR_UNEXPECTED;
}
mDNSHost.Truncate();
}
return rv;
}
// this might get exposed to clients, so we've broken it
// out of the destructor.
void
nsLDAPConnection::Close()
{
int rc;
MOZ_LOG(gLDAPLogModule, mozilla::LogLevel::Debug, ("unbinding\n"));
if (mConnectionHandle) {
// note that the ldap_unbind() call in the 5.0 version of the LDAP C SDK
// appears to be exactly identical to ldap_unbind_s(), so it may in fact
// still be synchronous
//
rc = ldap_unbind(mConnectionHandle);
#ifdef PR_LOGGING
if (rc != LDAP_SUCCESS) {
MOZ_LOG(gLDAPLogModule, mozilla::LogLevel::Warning,
("nsLDAPConnection::Close(): %s\n",
ldap_err2string(rc)));
}
#endif
mConnectionHandle = nullptr;
}
MOZ_LOG(gLDAPLogModule, mozilla::LogLevel::Debug, ("unbound\n"));
NS_ASSERTION(!mThread || NS_SUCCEEDED(mThread->Shutdown()),
"Failed to shutdown thread cleanly");
// Cancel the DNS lookup if needed, and also drop the reference to the
// Init listener (if still there).
//
if (mDNSRequest) {
mDNSRequest->Cancel(NS_ERROR_ABORT);
mDNSRequest = nullptr;
}
mInitListener = nullptr;
}
NS_IMETHODIMP
nsLDAPConnection::Observe(nsISupports *aSubject, const char *aTopic,
const char16_t *aData)
{
if (!strcmp(aTopic, "profile-change-net-teardown")) {
// Abort all ldap requests.
/* We cannot use enumerate function to abort operations because
* nsILDAPOperation::AbandonExt() is modifying list of operations
* and this leads to starvation.
* We have to do a copy of pending operations.
*/
nsTArray<nsILDAPOperation*> pending_operations;
{
MutexAutoLock lock(mPendingOperationsMutex);
for (auto iter = mPendingOperations.Iter(); !iter.Done(); iter.Next()) {
pending_operations.AppendElement(iter.UserData());
}
}
for (uint32_t i = 0; i < pending_operations.Length(); i++) {
pending_operations[i]->AbandonExt();
}
Close();
} else {
NS_NOTREACHED("unexpected topic");
return NS_ERROR_UNEXPECTED;
}
return NS_OK;
}
NS_IMETHODIMP
nsLDAPConnection::GetClosure(nsISupports **_retval)
{
if (!_retval) {
return NS_ERROR_ILLEGAL_VALUE;
}
NS_IF_ADDREF(*_retval = mClosure);
return NS_OK;
}
NS_IMETHODIMP
nsLDAPConnection::SetClosure(nsISupports *aClosure)
{
mClosure = aClosure;
return NS_OK;
}
// who we're binding as
//
// readonly attribute AUTF8String bindName
//
NS_IMETHODIMP
nsLDAPConnection::GetBindName(nsACString& _retval)
{
_retval.Assign(mBindName);
return NS_OK;
}
// wrapper for ldap_get_lderrno
// XXX should copy before returning
//
NS_IMETHODIMP
nsLDAPConnection::GetLdErrno(nsACString& matched, nsACString& errString,
int32_t *_retval)
{
char *match, *err;
NS_ENSURE_ARG_POINTER(_retval);
*_retval = ldap_get_lderrno(mConnectionHandle, &match, &err);
matched.Assign(match);
errString.Assign(err);
return NS_OK;
}
// return the error string corresponding to GetLdErrno.
//
// XXX - deal with optional params
// XXX - how does ldap_perror know to look at the global errno?
//
NS_IMETHODIMP
nsLDAPConnection::GetErrorString(char16_t **_retval)
{
NS_ENSURE_ARG_POINTER(_retval);
// get the error string
//
char *rv = ldap_err2string(ldap_get_lderrno(mConnectionHandle, 0, 0));
if (!rv) {
return NS_ERROR_OUT_OF_MEMORY;
}
// make a copy using the XPCOM shared allocator
//
*_retval = ToNewUnicode(NS_ConvertUTF8toUTF16(rv));
if (!*_retval) {
return NS_ERROR_OUT_OF_MEMORY;
}
return NS_OK;
}
/**
* Add an nsILDAPOperation to the list of operations pending on
* this connection. This is also mainly intended for use by the
* nsLDAPOperation code.
*/
nsresult
nsLDAPConnection::AddPendingOperation(uint32_t aOperationID, nsILDAPOperation *aOperation)
{
NS_ENSURE_ARG_POINTER(aOperation);
nsIRunnable* runnable = new nsLDAPConnectionRunnable(aOperationID, aOperation,
this);
{
MutexAutoLock lock(mPendingOperationsMutex);
mPendingOperations.Put((uint32_t)aOperationID, aOperation);
MOZ_LOG(gLDAPLogModule, mozilla::LogLevel::Debug,
("pending operation added; total pending operations now = %d\n",
mPendingOperations.Count()));
}
nsresult rv;
if (!mThread)
{
rv = NS_NewThread(getter_AddRefs(mThread), runnable);
NS_ENSURE_SUCCESS(rv, rv);
}
else
{
rv = mThread->Dispatch(runnable, nsIEventTarget::DISPATCH_NORMAL);
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}
/**
* Remove an nsILDAPOperation from the list of operations pending on this
* connection. Mainly intended for use by the nsLDAPOperation code.
*
* @param aOperation operation to add
* @exception NS_ERROR_INVALID_POINTER aOperation was NULL
* @exception NS_ERROR_OUT_OF_MEMORY out of memory
* @exception NS_ERROR_FAILURE could not delete the operation
*
* void removePendingOperation(in nsILDAPOperation aOperation);
*/
nsresult
nsLDAPConnection::RemovePendingOperation(uint32_t aOperationID)
{
NS_ENSURE_TRUE(aOperationID > 0, NS_ERROR_UNEXPECTED);
MOZ_LOG(gLDAPLogModule, mozilla::LogLevel::Debug,
("nsLDAPConnection::RemovePendingOperation(): operation removed\n"));
{
MutexAutoLock lock(mPendingOperationsMutex);
mPendingOperations.Remove(aOperationID);
MOZ_LOG(gLDAPLogModule, mozilla::LogLevel::Debug,
("nsLDAPConnection::RemovePendingOperation(): operation "
"removed; total pending operations now = %d\n",
mPendingOperations.Count()));
}
return NS_OK;
}
class nsOnLDAPMessageRunnable : public Runnable
{
public:
nsOnLDAPMessageRunnable(nsLDAPMessage *aMsg, bool aClear)
: m_msg(aMsg)
, m_clear(aClear)
{}
NS_DECL_NSIRUNNABLE
private:
RefPtr<nsLDAPMessage> m_msg;
bool m_clear;
};
NS_IMETHODIMP nsOnLDAPMessageRunnable::Run()
{
// get the message listener object.
nsLDAPOperation *nsoperation = static_cast<nsLDAPOperation *>(m_msg->mOperation.get());
nsCOMPtr<nsILDAPMessageListener> listener;
nsresult rv = nsoperation->GetMessageListener(getter_AddRefs(listener));
if (m_clear)
{
// try to break cycles
nsoperation->Clear();
}
if (!listener)
{
NS_ERROR("nsLDAPConnection::InvokeMessageCallback(): probable "
"memory corruption: GetMessageListener() returned nullptr");
return rv;
}
return listener->OnLDAPMessage(m_msg);
}
nsresult
nsLDAPConnection::InvokeMessageCallback(LDAPMessage *aMsgHandle,
nsILDAPMessage *aMsg,
int32_t aOperation,
bool aRemoveOpFromConnQ)
{
#if defined(DEBUG)
// We only want this being logged for debug builds so as not to affect performance too much.
MOZ_LOG(gLDAPLogModule, mozilla::LogLevel::Debug, ("InvokeMessageCallback entered\n"));
#endif
// Get the operation.
nsCOMPtr<nsILDAPOperation> operation;
{
MutexAutoLock lock(mPendingOperationsMutex);
mPendingOperations.Get((uint32_t)aOperation, getter_AddRefs(operation));
}
NS_ENSURE_TRUE(operation, NS_ERROR_NULL_POINTER);
nsLDAPMessage *msg = static_cast<nsLDAPMessage *>(aMsg);
msg->mOperation = operation;
// proxy the listener callback to the ui thread.
RefPtr<nsOnLDAPMessageRunnable> runnable =
new nsOnLDAPMessageRunnable(msg, aRemoveOpFromConnQ);
// invoke the callback
NS_DispatchToMainThread(runnable);
// if requested (ie the operation is done), remove the operation
// from the connection queue.
if (aRemoveOpFromConnQ)
{
MutexAutoLock lock(mPendingOperationsMutex);
mPendingOperations.Remove(aOperation);
MOZ_LOG(gLDAPLogModule, mozilla::LogLevel::Debug,
("pending operation removed; total pending operations now ="
" %d\n", mPendingOperations.Count()));
}
return NS_OK;
}
NS_IMETHODIMP
nsLDAPConnection::OnLookupComplete(nsICancelable *aRequest,
nsIDNSRecord *aRecord,
nsresult aStatus)
{
nsresult rv = NS_OK;
if (aRecord) {
// Build mResolvedIP list
//
mResolvedIP.Truncate();
int32_t index = 0;
nsCString addrbuf;
nsCOMPtr<nsINetAddr> addr;
while (NS_SUCCEEDED(aRecord->GetScriptableNextAddr(0, getter_AddRefs(addr)))) {
// We can only use v4 addresses
//
uint16_t family = 0;
bool v4mapped = false;
addr->GetFamily(&family);
addr->GetIsV4Mapped(&v4mapped);
if (family == nsINetAddr::FAMILY_INET || v4mapped) {
// If there are more IPs in the list, we separate them with
// a space, as supported/used by the LDAP C-SDK.
//
if (index++)
mResolvedIP.Append(' ');
// Convert the IPv4 address to a string, and append it to our
// list of IPs. Strip leading '::FFFF:' (the IPv4-mapped-IPv6
// indicator) if present.
//
addr->GetAddress(addrbuf);
if (addrbuf[0] == ':' && addrbuf.Length() > 7)
mResolvedIP.Append(Substring(addrbuf, 7));
else
mResolvedIP.Append(addrbuf);
}
}
}
if (NS_FAILED(aStatus)) {
// The DNS service failed, lets pass something reasonable
// back to the listener.
//
switch (aStatus) {
case NS_ERROR_OUT_OF_MEMORY:
case NS_ERROR_UNKNOWN_HOST:
case NS_ERROR_FAILURE:
case NS_ERROR_OFFLINE:
rv = aStatus;
break;
default:
rv = NS_ERROR_UNEXPECTED;
break;
}
} else if (!mResolvedIP.Length()) {
// We have no host resolved, that is very bad, and should most
// likely have been caught earlier.
//
NS_ERROR("nsLDAPConnection::OnStopLookup(): the resolved IP "
"string is empty.\n");
rv = NS_ERROR_UNKNOWN_HOST;
} else {
// We've got the IP(s) for the hostname, now lets setup the
// LDAP connection using this information. Note that if the
// LDAP server returns a referral, the C-SDK will perform a
// new, synchronous DNS lookup, which might hang (but hopefully
// if we've come this far, DNS is working properly).
//
mConnectionHandle = ldap_init(mResolvedIP.get(),
mPort == -1 ?
(mSSL ? LDAPS_PORT : LDAP_PORT) : mPort);
// Check that we got a proper connection, and if so, setup the
// threading functions for this connection.
//
if ( !mConnectionHandle ) {
rv = NS_ERROR_FAILURE; // LDAP C SDK API gives no useful error
} else {
#if defined(DEBUG_dmose) || defined(DEBUG_bienvenu)
const int lDebug = 0;
ldap_set_option(mConnectionHandle, LDAP_OPT_DEBUG_LEVEL, &lDebug);
#endif
// the C SDK currently defaults to v2. if we're to use v3,
// tell it so.
//
int version;
switch (mVersion) {
case 2:
break;
case 3:
version = LDAP_VERSION3;
ldap_set_option(mConnectionHandle, LDAP_OPT_PROTOCOL_VERSION,
&version);
break;
default:
NS_ERROR("nsLDAPConnection::OnLookupComplete(): mVersion"
" invalid");
}
// This code sets up the current connection to use PSM for SSL
// functionality. Making this use libssldap instead for
// non-browser user shouldn't be hard.
extern nsresult nsLDAPInstallSSL(LDAP *ld, const char *aHostName);
if (mSSL) {
if (ldap_set_option(mConnectionHandle, LDAP_OPT_SSL,
LDAP_OPT_ON) != LDAP_SUCCESS ) {
NS_ERROR("nsLDAPConnection::OnStopLookup(): Error"
" configuring connection to use SSL");
rv = NS_ERROR_UNEXPECTED;
}
rv = nsLDAPInstallSSL(mConnectionHandle, mDNSHost.get());
if (NS_FAILED(rv)) {
NS_ERROR("nsLDAPConnection::OnStopLookup(): Error"
" installing secure LDAP routines for"
" connection");
}
}
}
}
// Drop the DNS request object, we no longer need it, and set the flag
// indicating that DNS has finished.
//
mDNSRequest = nullptr;
mDNSHost.Truncate();
// Call the listener, and then we can release our reference to it.
//
mInitListener->OnLDAPInit(this, rv);
mInitListener = nullptr;
return rv;
}
nsLDAPConnectionRunnable::nsLDAPConnectionRunnable(int32_t aOperationID,
nsILDAPOperation *aOperation,
nsLDAPConnection *aConnection)
: mOperationID(aOperationID), mConnection(aConnection)
{
}
nsLDAPConnectionRunnable::~nsLDAPConnectionRunnable()
{
if (mConnection) {
NS_ReleaseOnMainThread(mConnection.forget());
}
}
NS_IMPL_ISUPPORTS(nsLDAPConnectionRunnable, nsIRunnable)
NS_IMETHODIMP nsLDAPConnectionRunnable::Run()
{
if (!mOperationID) {
NS_ERROR("mOperationID is null");
return NS_ERROR_NULL_POINTER;
}
LDAPMessage *msgHandle;
bool operationFinished = true;
RefPtr<nsLDAPMessage> msg;
struct timeval timeout = { 0, 0 };
nsCOMPtr<nsIThread> thread = do_GetCurrentThread();
int32_t returnCode = ldap_result(mConnection->mConnectionHandle, mOperationID, LDAP_MSG_ONE, &timeout, &msgHandle);
switch (returnCode)
{
// timeout
case 0:
// XXX do we need a timer?
return thread->Dispatch(this, nsIEventTarget::DISPATCH_NORMAL);
case -1:
NS_ERROR("We don't know what went wrong with the ldap operation");
return NS_ERROR_FAILURE;
case LDAP_RES_SEARCH_ENTRY:
case LDAP_RES_SEARCH_REFERENCE:
// XXX what should we do with LDAP_RES_SEARCH_EXTENDED
operationFinished = false;
MOZ_FALLTHROUGH;
default:
{
msg = new nsLDAPMessage;
if (!msg)
return NS_ERROR_NULL_POINTER;
// initialize the message, using a protected method not available
// through nsILDAPMessage (which is why we need the raw pointer)
nsresult rv = msg->Init(mConnection, msgHandle);
switch (rv)
{
case NS_OK:
{
int32_t errorCode;
msg->GetErrorCode(&errorCode);
// maybe a version error, e.g., using v3 on a v2 server.
// if we're using v3, try v2.
if (errorCode == LDAP_PROTOCOL_ERROR &&
mConnection->mVersion == nsILDAPConnection::VERSION3)
{
nsAutoCString password;
mConnection->mVersion = nsILDAPConnection::VERSION2;
ldap_set_option(mConnection->mConnectionHandle,
LDAP_OPT_PROTOCOL_VERSION, &mConnection->mVersion);
if (NS_SUCCEEDED(rv))
{
// We don't want to notify callers that we are done, so
// redispatch the runnable.
// XXX do we need a timer?
rv = thread->Dispatch(this, nsIEventTarget::DISPATCH_NORMAL);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
}
// If we're midway through a SASL Bind, we need to continue
// without letting our caller know what we're up to!
//
if (errorCode == LDAP_SASL_BIND_IN_PROGRESS) {
struct berval *creds;
ldap_parse_sasl_bind_result(
mConnection->mConnectionHandle, msgHandle,
&creds, 0);
nsCOMPtr<nsILDAPOperation> operation;
{
MutexAutoLock lock(mConnection->mPendingOperationsMutex);
mConnection->mPendingOperations.Get((uint32_t)mOperationID, getter_AddRefs(operation));
}
NS_ENSURE_TRUE(operation, NS_ERROR_NULL_POINTER);
nsresult rv = operation->SaslStep(creds->bv_val, creds->bv_len);
if (NS_SUCCEEDED(rv))
return NS_OK;
}
break;
}
// Error code handling in here
default:
return NS_OK;
}
// invoke the callback on the nsILDAPOperation corresponding to
// this message
rv = mConnection->InvokeMessageCallback(msgHandle, msg, mOperationID,
operationFinished);
if (NS_FAILED(rv))
{
NS_ERROR("CheckLDAPOperationResult(): error invoking message"
" callback");
// punt and hope things work out better next time around
return NS_OK;
}
if (!operationFinished)
{
// XXX do we need a timer?
rv = thread->Dispatch(this, nsIEventTarget::DISPATCH_NORMAL);
NS_ENSURE_SUCCESS(rv, rv);
}
break;
}
}
return NS_OK;
}

View file

@ -0,0 +1,139 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _nsLDAPConnection_h_
#define _nsLDAPConnection_h_
#include "nsILDAPConnection.h"
#include "ldap.h"
#include "nsStringGlue.h"
#include "nsIThread.h"
#include "nsIRunnable.h"
#include "nsCOMPtr.h"
#include "nsILDAPMessageListener.h"
#include "nsInterfaceHashtable.h"
#include "nspr.h"
#include "nsWeakReference.h"
#include "nsWeakPtr.h"
#include "nsIDNSListener.h"
#include "nsICancelable.h"
#include "nsIRequest.h"
#include "nsCOMArray.h"
#include "nsIObserver.h"
#include "nsAutoPtr.h"
#include "mozilla/Mutex.h"
/**
* Casting nsILDAPConnection to nsISupports is ambiguous.
* This method handles that.
*/
inline nsISupports*
ToSupports(nsILDAPConnection* p)
{
return NS_ISUPPORTS_CAST(nsILDAPConnection*, p);
}
// 0d871e30-1dd2-11b2-8ea9-831778c78e93
//
#define NS_LDAPCONNECTION_CID \
{ 0x0d871e30, 0x1dd2, 0x11b2, \
{ 0x8e, 0xa9, 0x83, 0x17, 0x78, 0xc7, 0x8e, 0x93 }}
class nsLDAPConnection : public nsILDAPConnection,
public nsSupportsWeakReference,
public nsIDNSListener,
public nsIObserver
{
friend class nsLDAPOperation;
friend class nsLDAPMessage;
friend class nsLDAPConnectionRunnable;
typedef mozilla::Mutex Mutex;
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSILDAPCONNECTION
NS_DECL_NSIDNSLISTENER
NS_DECL_NSIOBSERVER
// constructor & destructor
//
nsLDAPConnection();
protected:
virtual ~nsLDAPConnection();
// invoke the callback associated with a given message, and possibly
// delete it from the connection queue
//
nsresult InvokeMessageCallback(LDAPMessage *aMsgHandle,
nsILDAPMessage *aMsg,
int32_t aOperation,
bool aRemoveOpFromConnQ);
/**
* Add an nsILDAPOperation to the list of operations pending on
* this connection. This is mainly intended for use by the
* nsLDAPOperation code. Used so that the thread waiting on messages
* for this connection has an operation to callback to.
*
* @param aOperation operation to add
* @exception NS_ERROR_ILLEGAL_VALUE aOperation was NULL
* @exception NS_ERROR_UNEXPECTED this operation's msgId was not
* unique to this connection
* @exception NS_ERROR_OUT_OF_MEMORY out of memory
*/
nsresult AddPendingOperation(uint32_t aOperationID, nsILDAPOperation *aOperation);
/**
* Remove an nsILDAPOperation from the list of operations pending on this
* connection. Mainly intended for use by the nsLDAPOperation code.
*
* @param aOperation operation to add
* @exception NS_ERROR_INVALID_POINTER aOperation was NULL
* @exception NS_ERROR_OUT_OF_MEMORY out of memory
* @exception NS_ERROR_FAILURE could not delete the operation
*/
nsresult RemovePendingOperation(uint32_t aOperationID);
void Close(); // close the connection
LDAP *mConnectionHandle; // the LDAP C SDK's connection object
nsCString mBindName; // who to bind as
nsCOMPtr<nsIThread> mThread; // thread which marshals results
Mutex mPendingOperationsMutex;
nsInterfaceHashtable<nsUint32HashKey, nsILDAPOperation> mPendingOperations;
int32_t mPort; // The LDAP port we're binding to
bool mSSL; // the options
uint32_t mVersion; // LDAP protocol version
nsCString mResolvedIP; // Preresolved list of host IPs
nsCOMPtr<nsILDAPMessageListener> mInitListener; // Init callback
nsCOMPtr<nsICancelable> mDNSRequest; // The "active" DNS request
nsCString mDNSHost; // The hostname being resolved
nsCOMPtr<nsISupports> mClosure; // private parameter (anything caller desires)
};
class nsLDAPConnectionRunnable : public nsIRunnable
{
friend class nsLDAPConnection;
friend class nsLDAPMessage;
public:
nsLDAPConnectionRunnable(int32_t aOperationID,
nsILDAPOperation *aOperation,
nsLDAPConnection *aConnection);
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIRUNNABLE
int32_t mOperationID;
RefPtr<nsLDAPConnection> mConnection;
private:
virtual ~nsLDAPConnectionRunnable();
};
#endif // _nsLDAPConnection_h_

View file

@ -0,0 +1,122 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsLDAPControl.h"
#include "prmem.h"
#include "plstr.h"
#include "nsLDAPBERValue.h"
NS_IMPL_ISUPPORTS(nsLDAPControl, nsILDAPControl)
nsLDAPControl::nsLDAPControl()
: mIsCritical(false)
{
}
nsLDAPControl::~nsLDAPControl()
{
}
/* attribute ACString oid; */
NS_IMETHODIMP nsLDAPControl::GetOid(nsACString & aOid)
{
aOid.Assign(mOid);
return NS_OK;
}
NS_IMETHODIMP nsLDAPControl::SetOid(const nsACString & aOid)
{
mOid = aOid;
return NS_OK;
}
/* attribute nsILDAPBERValue value; */
NS_IMETHODIMP
nsLDAPControl::GetValue(nsILDAPBERValue * *aValue)
{
NS_IF_ADDREF(*aValue = mValue);
return NS_OK;
}
NS_IMETHODIMP
nsLDAPControl::SetValue(nsILDAPBERValue * aValue)
{
mValue = aValue;
return NS_OK;
}
/* attribute boolean isCritical; */
NS_IMETHODIMP
nsLDAPControl::GetIsCritical(bool *aIsCritical)
{
*aIsCritical = mIsCritical;
return NS_OK;
}
NS_IMETHODIMP
nsLDAPControl::SetIsCritical(bool aIsCritical)
{
mIsCritical = aIsCritical;
return NS_OK;
}
/**
* utility routine for use inside the LDAP XPCOM SDK
*/
nsresult
nsLDAPControl::ToLDAPControl(LDAPControl **control)
{
// because nsLDAPProtocolModule::Init calls prldap_install_routines we know
// that the C SDK will be using the NSPR allocator under the hood, so our
// callers will therefore be able to use ldap_control_free() and friends on
// this control.
LDAPControl *ctl = static_cast<LDAPControl *>(PR_Calloc(1, sizeof(LDAPControl)));
if (!ctl) {
return NS_ERROR_OUT_OF_MEMORY;
}
// need to ensure that this string is also alloced by PR_Alloc
ctl->ldctl_oid = PL_strdup(mOid.get());
if (!ctl->ldctl_oid) {
PR_Free(ctl);
return NS_ERROR_OUT_OF_MEMORY;
}
ctl->ldctl_iscritical = mIsCritical;
if (!mValue) {
// no data associated with this control
ctl->ldctl_value.bv_len = 0;
ctl->ldctl_value.bv_val = 0;
} else {
// just to make the code below a bit more readable
nsLDAPBERValue *nsBerVal =
static_cast<nsLDAPBERValue *>(static_cast<nsILDAPBERValue *>
(mValue.get()));
ctl->ldctl_value.bv_len = nsBerVal->mSize;
if (!nsBerVal->mSize) {
// a zero-length value is associated with this control
return NS_ERROR_NOT_IMPLEMENTED;
} else {
// same for the berval itself
ctl->ldctl_value.bv_len = nsBerVal->mSize;
ctl->ldctl_value.bv_val = static_cast<char *>
(PR_Malloc(nsBerVal->mSize));
if (!ctl->ldctl_value.bv_val) {
ldap_control_free(ctl);
return NS_ERROR_OUT_OF_MEMORY;
}
memcpy(ctl->ldctl_value.bv_val, nsBerVal->mValue,
ctl->ldctl_value.bv_len);
}
}
*control = ctl;
return NS_OK;
}

View file

@ -0,0 +1,42 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsILDAPControl.h"
#include "nsCOMPtr.h"
#include "nsILDAPBERValue.h"
#include "nsStringGlue.h"
#include "ldap.h"
// {5B608BBE-C0EA-4f74-B209-9CDCD79EC401}
#define NS_LDAPCONTROL_CID \
{ 0x5b608bbe, 0xc0ea, 0x4f74, \
{ 0xb2, 0x9, 0x9c, 0xdc, 0xd7, 0x9e, 0xc4, 0x1 } }
class nsLDAPControl final : public nsILDAPControl
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSILDAPCONTROL
nsLDAPControl();
/**
* return a pointer to C-SDK compatible LDAPControl structure. Note that
* this is allocated with NS_Alloc and must be freed with NS_Free, both by
* ldap_control_free() and friends.
*
* @exception null pointer return if allocation failed
*/
nsresult ToLDAPControl(LDAPControl **aControl);
private:
~nsLDAPControl();
protected:
nsCOMPtr<nsILDAPBERValue> mValue; // the value portion of this control
bool mIsCritical; // should server abort if control not understood?
nsCString mOid; // Object ID for this control
};

View file

@ -0,0 +1,11 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "prlog.h"
#ifdef PR_LOGGING
extern PRLogModuleInfo *gLDAPLogModule; // defn in nsLDAPProtocolModule.cpp
#endif

View file

@ -0,0 +1,649 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsLDAPInternal.h"
#include "nsLDAPMessage.h"
#include "nspr.h"
#include "nsDebug.h"
#include "nsMemory.h"
#include "nsLDAPConnection.h"
#include "nsISupportsUtils.h"
#include "nsLDAPBERValue.h"
#include "nsILDAPErrors.h"
#include "nsIClassInfoImpl.h"
#include "nsLDAPUtils.h"
#include "mozilla/Logging.h"
NS_IMPL_CLASSINFO(nsLDAPMessage, NULL, nsIClassInfo::THREADSAFE,
NS_LDAPMESSAGE_CID)
NS_IMPL_ADDREF(nsLDAPMessage)
NS_IMPL_RELEASE(nsLDAPMessage)
NS_INTERFACE_MAP_BEGIN(nsLDAPMessage)
NS_INTERFACE_MAP_ENTRY(nsILDAPMessage)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsILDAPMessage)
NS_IMPL_QUERY_CLASSINFO(nsLDAPMessage)
NS_INTERFACE_MAP_END_THREADSAFE
NS_IMPL_CI_INTERFACE_GETTER(nsLDAPMessage, nsILDAPMessage)
// constructor
//
nsLDAPMessage::nsLDAPMessage()
: mMsgHandle(0),
mErrorCode(LDAP_SUCCESS),
mMatchedDn(0),
mErrorMessage(0),
mReferrals(0),
mServerControls(0)
{
}
// destructor
//
nsLDAPMessage::~nsLDAPMessage(void)
{
if (mMsgHandle) {
int rc = ldap_msgfree(mMsgHandle);
// If you are having problems compiling the following code on a Solaris
// machine with the Forte 6 Update 1 compilers, then you need to make
// sure you have applied all the required patches. See:
// http://www.mozilla.org/unix/solaris-build.html for more details.
switch(rc) {
case LDAP_RES_BIND:
case LDAP_RES_SEARCH_ENTRY:
case LDAP_RES_SEARCH_RESULT:
case LDAP_RES_MODIFY:
case LDAP_RES_ADD:
case LDAP_RES_DELETE:
case LDAP_RES_MODRDN:
case LDAP_RES_COMPARE:
case LDAP_RES_SEARCH_REFERENCE:
case LDAP_RES_EXTENDED:
case LDAP_RES_ANY:
// success
break;
case LDAP_SUCCESS:
// timed out (dunno why LDAP_SUCCESS is used to indicate this)
MOZ_LOG(gLDAPLogModule, mozilla::LogLevel::Warning,
("nsLDAPMessage::~nsLDAPMessage: ldap_msgfree() "
"timed out\n"));
break;
default:
// other failure
MOZ_LOG(gLDAPLogModule, mozilla::LogLevel::Warning,
("nsLDAPMessage::~nsLDAPMessage: ldap_msgfree() "
"failed: %s\n", ldap_err2string(rc)));
break;
}
}
if (mMatchedDn) {
ldap_memfree(mMatchedDn);
}
if (mErrorMessage) {
ldap_memfree(mErrorMessage);
}
if (mReferrals) {
ldap_value_free(mReferrals);
}
if (mServerControls) {
ldap_controls_free(mServerControls);
}
}
/**
* Initializes a message.
*
* @param aConnection The nsLDAPConnection this message is on
* @param aMsgHandle The native LDAPMessage to be wrapped.
*
* @exception NS_ERROR_ILLEGAL_VALUE null pointer passed in
* @exception NS_ERROR_UNEXPECTED internal err; shouldn't happen
* @exception NS_ERROR_LDAP_DECODING_ERROR problem during BER decoding
* @exception NS_ERROR_OUT_OF_MEMORY ran out of memory
*/
nsresult
nsLDAPMessage::Init(nsILDAPConnection *aConnection, LDAPMessage *aMsgHandle)
{
int parseResult;
if (!aConnection || !aMsgHandle) {
NS_WARNING("Null pointer passed in to nsLDAPMessage::Init()");
return NS_ERROR_ILLEGAL_VALUE;
}
// initialize the appropriate member vars
//
mConnection = aConnection;
mMsgHandle = aMsgHandle;
// cache the connection handle. we're violating the XPCOM type-system
// here since we're a friend of the connection class and in the
// same module.
//
mConnectionHandle = static_cast<nsLDAPConnection *>(aConnection)->mConnectionHandle;
// do any useful message parsing
//
const int msgType = ldap_msgtype(mMsgHandle);
if ( msgType == -1) {
NS_ERROR("nsLDAPMessage::Init(): ldap_msgtype() failed");
return NS_ERROR_UNEXPECTED;
}
switch (msgType) {
case LDAP_RES_SEARCH_REFERENCE:
// XXX should do something here?
break;
case LDAP_RES_SEARCH_ENTRY:
// nothing to do here
break;
case LDAP_RES_EXTENDED:
// XXX should do something here?
break;
case LDAP_RES_BIND:
case LDAP_RES_SEARCH_RESULT:
case LDAP_RES_MODIFY:
case LDAP_RES_ADD:
case LDAP_RES_DELETE:
case LDAP_RES_MODRDN:
case LDAP_RES_COMPARE:
parseResult = ldap_parse_result(mConnectionHandle,
mMsgHandle, &mErrorCode, &mMatchedDn,
&mErrorMessage,&mReferrals,
&mServerControls, 0);
switch (parseResult) {
case LDAP_SUCCESS:
// we're good
break;
case LDAP_DECODING_ERROR:
NS_WARNING("nsLDAPMessage::Init(): ldap_parse_result() hit a "
"decoding error");
return NS_ERROR_LDAP_DECODING_ERROR;
case LDAP_NO_MEMORY:
NS_WARNING("nsLDAPMessage::Init(): ldap_parse_result() ran out "
"of memory");
return NS_ERROR_OUT_OF_MEMORY;
case LDAP_PARAM_ERROR:
case LDAP_MORE_RESULTS_TO_RETURN:
case LDAP_NO_RESULTS_RETURNED:
default:
NS_ERROR("nsLDAPMessage::Init(): ldap_parse_result returned "
"unexpected return code");
return NS_ERROR_UNEXPECTED;
}
break;
default:
NS_ERROR("nsLDAPMessage::Init(): unexpected message type");
return NS_ERROR_UNEXPECTED;
}
return NS_OK;
}
/**
* The result code of the (possibly partial) operation.
*
* @exception NS_ERROR_ILLEGAL_VALUE null pointer passed in
*
* readonly attribute long errorCode;
*/
NS_IMETHODIMP
nsLDAPMessage::GetErrorCode(int32_t *aErrorCode)
{
if (!aErrorCode) {
return NS_ERROR_ILLEGAL_VALUE;
}
*aErrorCode = mErrorCode;
return NS_OK;
}
NS_IMETHODIMP
nsLDAPMessage::GetType(int32_t *aType)
{
if (!aType) {
return NS_ERROR_ILLEGAL_VALUE;
}
*aType = ldap_msgtype(mMsgHandle);
if (*aType == -1) {
return NS_ERROR_UNEXPECTED;
};
return NS_OK;
}
// we don't get to use exceptions, so we'll fake it. this is an error
// handler for IterateAttributes().
//
nsresult
nsLDAPMessage::IterateAttrErrHandler(int32_t aLderrno, uint32_t *aAttrCount,
char** *aAttributes, BerElement *position)
{
// if necessary, free the position holder used by
// ldap_{first,next}_attribute()
//
if (position) {
ldap_ber_free(position, 0);
}
// deallocate any entries in the array that have been allocated, then
// the array itself
//
if (*aAttributes) {
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(*aAttrCount, *aAttributes);
}
// possibly spit out a debugging message, then return an appropriate
// error code
//
switch (aLderrno) {
case LDAP_PARAM_ERROR:
NS_WARNING("nsLDAPMessage::IterateAttributes() failure; probable bug "
"or memory corruption encountered");
return NS_ERROR_UNEXPECTED;
break;
case LDAP_DECODING_ERROR:
NS_WARNING("nsLDAPMessage::IterateAttributes(): decoding error");
return NS_ERROR_LDAP_DECODING_ERROR;
break;
case LDAP_NO_MEMORY:
return NS_ERROR_OUT_OF_MEMORY;
break;
}
NS_WARNING("nsLDAPMessage::IterateAttributes(): LDAP C SDK returned "
"unexpected value; possible bug or memory corruption");
return NS_ERROR_UNEXPECTED;
}
// wrapper for ldap_first_attribute
//
NS_IMETHODIMP
nsLDAPMessage::GetAttributes(uint32_t *aAttrCount, char** *aAttributes)
{
return IterateAttributes(aAttrCount, aAttributes, true);
}
// if getP is true, we get the attributes by recursing once
// (without getP set) in order to fill in *attrCount, then allocate
// and fill in the *aAttributes.
//
// if getP is false, just fill in *attrCount and return
//
nsresult
nsLDAPMessage::IterateAttributes(uint32_t *aAttrCount, char** *aAttributes,
bool getP)
{
BerElement *position;
nsresult rv;
if (!aAttrCount || !aAttributes ) {
return NS_ERROR_INVALID_POINTER;
}
// if we've been called from GetAttributes, recurse once in order to
// count the elements in this message.
//
if (getP) {
*aAttributes = 0;
*aAttrCount = 0;
rv = IterateAttributes(aAttrCount, aAttributes, false);
if (NS_FAILED(rv))
return rv;
// create an array of the appropriate size
//
*aAttributes = static_cast<char **>(moz_xmalloc(*aAttrCount *
sizeof(char *)));
if (!*aAttributes) {
return NS_ERROR_OUT_OF_MEMORY;
}
}
// get the first attribute
//
char *attr = ldap_first_attribute(mConnectionHandle,
mMsgHandle,
&position);
if (!attr) {
return IterateAttrErrHandler(ldap_get_lderrno(mConnectionHandle, 0, 0),
aAttrCount, aAttributes, position);
}
// if we're getting attributes, try and fill in the first field
//
if (getP) {
(*aAttributes)[0] = NS_strdup(attr);
if (!(*aAttributes)[0]) {
ldap_memfree(attr);
free(*aAttributes);
return NS_ERROR_OUT_OF_MEMORY;
}
// note that we start counting again, in order to keep our place in
// the array so that we can unwind gracefully and avoid leakage if
// we hit an error as we're filling in the array
//
*aAttrCount = 1;
} else {
// otherwise just update the count
//
*aAttrCount = 1;
}
ldap_memfree(attr);
while (1) {
// get the next attribute
//
attr = ldap_next_attribute(mConnectionHandle, mMsgHandle, position);
// check to see if there is an error, or if we're just done iterating
//
if (!attr) {
// bail out if there's an error
//
int32_t lderrno = ldap_get_lderrno(mConnectionHandle, 0, 0);
if (lderrno != LDAP_SUCCESS) {
return IterateAttrErrHandler(lderrno, aAttrCount, aAttributes,
position);
}
// otherwise, there are no more attributes; we're done with
// the while loop
//
break;
} else if (getP) {
// if ldap_next_attribute did return successfully, and
// we're supposed to fill in a value, do so.
//
(*aAttributes)[*aAttrCount] = NS_strdup(attr);
if (!(*aAttributes)[*aAttrCount]) {
ldap_memfree(attr);
return IterateAttrErrHandler(LDAP_NO_MEMORY, aAttrCount,
aAttributes, position);
}
}
ldap_memfree(attr);
// we're done using *aAttrCount as a c-style array index (ie starting
// at 0). update it to reflect the number of elements now in the array
//
*aAttrCount += 1;
}
// free the position pointer, if necessary
//
if (position) {
ldap_ber_free(position, 0);
}
return NS_OK;
}
// readonly attribute wstring dn;
NS_IMETHODIMP nsLDAPMessage::GetDn(nsACString& aDn)
{
char *rawDn = ldap_get_dn(mConnectionHandle, mMsgHandle);
if (!rawDn) {
int32_t lderrno = ldap_get_lderrno(mConnectionHandle, 0, 0);
switch (lderrno) {
case LDAP_DECODING_ERROR:
NS_WARNING("nsLDAPMessage::GetDn(): ldap decoding error");
return NS_ERROR_LDAP_DECODING_ERROR;
case LDAP_PARAM_ERROR:
default:
NS_ERROR("nsLDAPMessage::GetDn(): internal error");
return NS_ERROR_UNEXPECTED;
}
}
MOZ_LOG(gLDAPLogModule, mozilla::LogLevel::Debug,
("nsLDAPMessage::GetDn(): dn = '%s'", rawDn));
aDn.Assign(rawDn);
ldap_memfree(rawDn);
return NS_OK;
}
// wrapper for ldap_get_values()
//
NS_IMETHODIMP
nsLDAPMessage::GetValues(const char *aAttr, uint32_t *aCount,
char16_t ***aValues)
{
char **values;
#if defined(DEBUG)
// We only want this being logged for debug builds so as not to affect performance too much.
MOZ_LOG(gLDAPLogModule, mozilla::LogLevel::Debug,
("nsLDAPMessage::GetValues(): called with aAttr = '%s'", aAttr));
#endif
values = ldap_get_values(mConnectionHandle, mMsgHandle, aAttr);
// bail out if there was a problem
//
if (!values) {
int32_t lderrno = ldap_get_lderrno(mConnectionHandle, 0, 0);
if ( lderrno == LDAP_DECODING_ERROR ) {
// this may not be an error; it could just be that the
// caller has asked for an attribute that doesn't exist.
//
MOZ_LOG(gLDAPLogModule, mozilla::LogLevel::Warning,
("nsLDAPMessage::GetValues(): ldap_get_values returned "
"LDAP_DECODING_ERROR"));
return NS_ERROR_LDAP_DECODING_ERROR;
} else if ( lderrno == LDAP_PARAM_ERROR ) {
NS_ERROR("nsLDAPMessage::GetValues(): internal error: 1");
return NS_ERROR_UNEXPECTED;
} else {
NS_ERROR("nsLDAPMessage::GetValues(): internal error: 2");
return NS_ERROR_UNEXPECTED;
}
}
// count the values
//
uint32_t numVals = ldap_count_values(values);
// create an array of the appropriate size
//
*aValues = static_cast<char16_t **>(moz_xmalloc(numVals * sizeof(char16_t *)));
if (!*aValues) {
ldap_value_free(values);
return NS_ERROR_OUT_OF_MEMORY;
}
// clone the array (except for the trailing NULL entry) using the
// shared allocator for XPCOM correctness
//
uint32_t i;
for ( i = 0 ; i < numVals ; i++ ) {
nsDependentCString sValue(values[i]);
if (IsUTF8(sValue))
(*aValues)[i] = ToNewUnicode(NS_ConvertUTF8toUTF16(sValue));
else
(*aValues)[i] = ToNewUnicode(NS_ConvertASCIItoUTF16(sValue));
if ( ! (*aValues)[i] ) {
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(i, aValues);
ldap_value_free(values);
return NS_ERROR_OUT_OF_MEMORY;
}
}
// now free our value array since we already cloned the values array
// to the 'aValues' results array.
ldap_value_free(values);
*aCount = numVals;
return NS_OK;
}
// wrapper for get_values_len
//
NS_IMETHODIMP
nsLDAPMessage::GetBinaryValues(const char *aAttr, uint32_t *aCount,
nsILDAPBERValue ***aValues)
{
struct berval **values;
#if defined(DEBUG)
// We only want this being logged for debug builds so as not to affect performance too much.
MOZ_LOG(gLDAPLogModule, mozilla::LogLevel::Debug,
("nsLDAPMessage::GetBinaryValues(): called with aAttr = '%s'",
aAttr));
#endif
values = ldap_get_values_len(mConnectionHandle, mMsgHandle, aAttr);
// bail out if there was a problem
//
if (!values) {
int32_t lderrno = ldap_get_lderrno(mConnectionHandle, 0, 0);
if ( lderrno == LDAP_DECODING_ERROR ) {
// this may not be an error; it could just be that the
// caller has asked for an attribute that doesn't exist.
//
MOZ_LOG(gLDAPLogModule, mozilla::LogLevel::Warning,
("nsLDAPMessage::GetBinaryValues(): ldap_get_values "
"returned LDAP_DECODING_ERROR"));
return NS_ERROR_LDAP_DECODING_ERROR;
} else if ( lderrno == LDAP_PARAM_ERROR ) {
NS_ERROR("nsLDAPMessage::GetBinaryValues(): internal error: 1");
return NS_ERROR_UNEXPECTED;
} else {
NS_ERROR("nsLDAPMessage::GetBinaryValues(): internal error: 2");
return NS_ERROR_UNEXPECTED;
}
}
// count the values
//
uint32_t numVals = ldap_count_values_len(values);
// create the out array
//
*aValues =
static_cast<nsILDAPBERValue **>(moz_xmalloc(numVals * sizeof(nsILDAPBERValue)));
if (!aValues) {
ldap_value_free_len(values);
return NS_ERROR_OUT_OF_MEMORY;
}
// clone the array (except for the trailing NULL entry) using the
// shared allocator for XPCOM correctness
//
uint32_t i;
nsresult rv;
for ( i = 0 ; i < numVals ; i++ ) {
// create an nsBERValue object
//
nsCOMPtr<nsILDAPBERValue> berValue = new nsLDAPBERValue();
if (!berValue) {
NS_ERROR("nsLDAPMessage::GetBinaryValues(): out of memory"
" creating nsLDAPBERValue object");
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(i, aValues);
ldap_value_free_len(values);
return NS_ERROR_OUT_OF_MEMORY;
}
// copy the value from the struct into the nsBERValue
//
rv = berValue->Set(values[i]->bv_len,
reinterpret_cast<uint8_t *>(values[i]->bv_val));
if (NS_FAILED(rv)) {
NS_ERROR("nsLDAPMessage::GetBinaryValues(): error setting"
" nsBERValue");
ldap_value_free_len(values);
return rv == NS_ERROR_OUT_OF_MEMORY ? rv : NS_ERROR_UNEXPECTED;
}
// put the nsIBERValue object into the out array
//
NS_ADDREF( (*aValues)[i] = berValue.get() );
}
*aCount = numVals;
ldap_value_free_len(values);
return NS_OK;
}
// readonly attribute nsILDAPOperation operation;
NS_IMETHODIMP nsLDAPMessage::GetOperation(nsILDAPOperation **_retval)
{
if (!_retval) {
NS_ERROR("nsLDAPMessage::GetOperation: null pointer ");
return NS_ERROR_NULL_POINTER;
}
NS_IF_ADDREF(*_retval = mOperation);
return NS_OK;
}
NS_IMETHODIMP
nsLDAPMessage::ToUnicode(char16_t* *aString)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsLDAPMessage::GetErrorMessage(nsACString & aErrorMessage)
{
aErrorMessage.Assign(mErrorMessage);
return NS_OK;
}
NS_IMETHODIMP
nsLDAPMessage::GetMatchedDn(nsACString & aMatchedDn)
{
aMatchedDn.Assign(mMatchedDn);
return NS_OK;
}

View file

@ -0,0 +1,66 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _nsLDAPMessage_h_
#define _nsLDAPMessage_h_
#include "ldap.h"
#include "nsILDAPMessage.h"
#include "nsILDAPOperation.h"
#include "nsCOMPtr.h"
// 76e061ad-a59f-43b6-b812-ee6e8e69423f
//
#define NS_LDAPMESSAGE_CID \
{ 0x76e061ad, 0xa59f, 0x43b6, \
{ 0xb8, 0x12, 0xee, 0x6e, 0x8e, 0x69, 0x42, 0x3f }}
class nsLDAPMessage : public nsILDAPMessage
{
friend class nsLDAPOperation;
friend class nsLDAPConnection;
friend class nsLDAPConnectionRunnable;
friend class nsOnLDAPMessageRunnable;
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSILDAPMESSAGE
// constructor & destructor
//
nsLDAPMessage();
protected:
virtual ~nsLDAPMessage();
nsresult IterateAttrErrHandler(int32_t aLderrno, uint32_t *aAttrCount,
char** *aAttributes, BerElement *position);
nsresult IterateAttributes(uint32_t *aAttrCount, char** *aAttributes,
bool getP);
nsresult Init(nsILDAPConnection *aConnection,
LDAPMessage *aMsgHandle);
LDAPMessage *mMsgHandle; // the message we're wrapping
nsCOMPtr<nsILDAPOperation> mOperation; // operation this msg relates to
LDAP *mConnectionHandle; // cached connection this op is on
// since we're caching the connection handle (above), we need to
// hold an owning ref to the relevant nsLDAPConnection object as long
// as we're around
//
nsCOMPtr<nsILDAPConnection> mConnection;
// the next five member vars are returned by ldap_parse_result()
//
int mErrorCode;
char *mMatchedDn;
char *mErrorMessage;
char **mReferrals;
LDAPControl **mServerControls;
};
#endif // _nsLDAPMessage_h

View file

@ -0,0 +1,158 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsLDAPModification.h"
#include "nsILDAPBERValue.h"
#include "nsISimpleEnumerator.h"
#include "nsServiceManagerUtils.h"
#include "nsComponentManagerUtils.h"
using namespace mozilla;
NS_IMPL_ISUPPORTS(nsLDAPModification, nsILDAPModification)
// constructor
//
nsLDAPModification::nsLDAPModification()
: mValuesLock("nsLDAPModification.mValuesLock")
{
}
// destructor
//
nsLDAPModification::~nsLDAPModification()
{
}
nsresult
nsLDAPModification::Init()
{
return NS_OK;
}
NS_IMETHODIMP
nsLDAPModification::GetOperation(int32_t *aOperation)
{
NS_ENSURE_ARG_POINTER(aOperation);
*aOperation = mOperation;
return NS_OK;
}
NS_IMETHODIMP nsLDAPModification::SetOperation(int32_t aOperation)
{
mOperation = aOperation;
return NS_OK;
}
NS_IMETHODIMP
nsLDAPModification::GetType(nsACString& aType)
{
aType.Assign(mType);
return NS_OK;
}
NS_IMETHODIMP
nsLDAPModification::SetType(const nsACString& aType)
{
mType.Assign(aType);
return NS_OK;
}
NS_IMETHODIMP
nsLDAPModification::GetValues(nsIArray** aResult)
{
NS_ENSURE_ARG_POINTER(aResult);
MutexAutoLock lock(mValuesLock);
if (!mValues)
return NS_ERROR_NOT_INITIALIZED;
NS_ADDREF(*aResult = mValues);
return NS_OK;
}
NS_IMETHODIMP
nsLDAPModification::SetValues(nsIArray* aValues)
{
NS_ENSURE_ARG_POINTER(aValues);
MutexAutoLock lock(mValuesLock);
nsresult rv;
if (!mValues)
mValues = do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
else
rv = mValues->Clear();
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsISimpleEnumerator> enumerator;
rv = aValues->Enumerate(getter_AddRefs(enumerator));
NS_ENSURE_SUCCESS(rv, rv);
bool hasMoreElements;
rv = enumerator->HasMoreElements(&hasMoreElements);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsISupports> value;
while (hasMoreElements)
{
rv = enumerator->GetNext(getter_AddRefs(value));
NS_ENSURE_SUCCESS(rv, rv);
rv = mValues->AppendElement(value, false);
NS_ENSURE_SUCCESS(rv, rv);
rv = enumerator->HasMoreElements(&hasMoreElements);
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}
NS_IMETHODIMP
nsLDAPModification::SetUpModification(int32_t aOperation,
const nsACString &aType,
nsIArray *aValues)
{
// Set the values using our local function before entering lock
// to avoid deadlocks due to holding the same lock twice.
nsresult rv = SetValues(aValues);
MutexAutoLock lock(mValuesLock);
mOperation = aOperation;
mType.Assign(aType);
return rv;
}
NS_IMETHODIMP
nsLDAPModification::SetUpModificationOneValue(int32_t aOperation,
const nsACString &aType,
nsILDAPBERValue *aValue)
{
NS_ENSURE_ARG_POINTER(aValue);
MutexAutoLock lock(mValuesLock);
mOperation = aOperation;
mType.Assign(aType);
nsresult rv;
if (!mValues)
mValues = do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
else
rv = mValues->Clear();
NS_ENSURE_SUCCESS(rv, rv);
return mValues->AppendElement(aValue, false);
}

View file

@ -0,0 +1,42 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _nsLDAPModification_h_
#define _nsLDAPModification_h_
#include "nsILDAPModification.h"
#include "nsIMutableArray.h"
#include "nsStringGlue.h"
#include "nsCOMPtr.h"
#include "mozilla/Mutex.h"
// 5b0f4d00-062e-11d6-a7f2-fc943c3c039c
//
#define NS_LDAPMODIFICATION_CID \
{ 0x5b0f4d00, 0x062e, 0x11d6, \
{ 0xa7, 0xf2, 0xfc, 0x94, 0x3c, 0x3c, 0x03, 0x9c }}
class nsLDAPModification : public nsILDAPModification
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSILDAPMODIFICATION
// constructor & destructor
//
nsLDAPModification();
nsresult Init();
private:
virtual ~nsLDAPModification();
int32_t mOperation;
nsCString mType;
nsCOMPtr<nsIMutableArray> mValues;
mozilla::Mutex mValuesLock;
};
#endif // _nsLDAPModification_h_

View file

@ -0,0 +1,975 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsLDAPInternal.h"
#include "nsLDAPOperation.h"
#include "nsLDAPBERValue.h"
#include "nsILDAPMessage.h"
#include "nsILDAPModification.h"
#include "nsIComponentManager.h"
#include "nspr.h"
#include "nsISimpleEnumerator.h"
#include "nsLDAPControl.h"
#include "nsILDAPErrors.h"
#include "nsIClassInfoImpl.h"
#include "nsIAuthModule.h"
#include "nsArrayUtils.h"
#include "nsMemory.h"
#include "mozilla/Logging.h"
// Helper function
static nsresult TranslateLDAPErrorToNSError(const int ldapError)
{
switch (ldapError) {
case LDAP_SUCCESS:
return NS_OK;
case LDAP_ENCODING_ERROR:
return NS_ERROR_LDAP_ENCODING_ERROR;
case LDAP_CONNECT_ERROR:
return NS_ERROR_LDAP_CONNECT_ERROR;
case LDAP_SERVER_DOWN:
return NS_ERROR_LDAP_SERVER_DOWN;
case LDAP_NO_MEMORY:
return NS_ERROR_OUT_OF_MEMORY;
case LDAP_NOT_SUPPORTED:
return NS_ERROR_LDAP_NOT_SUPPORTED;
case LDAP_PARAM_ERROR:
return NS_ERROR_INVALID_ARG;
case LDAP_FILTER_ERROR:
return NS_ERROR_LDAP_FILTER_ERROR;
default:
MOZ_LOG(gLDAPLogModule, mozilla::LogLevel::Error,
("TranslateLDAPErrorToNSError: "
"Do not know how to translate LDAP error: 0x%x", ldapError));
return NS_ERROR_UNEXPECTED;
}
}
// constructor
nsLDAPOperation::nsLDAPOperation()
{
}
// destructor
nsLDAPOperation::~nsLDAPOperation()
{
}
NS_IMPL_CLASSINFO(nsLDAPOperation, NULL, nsIClassInfo::THREADSAFE,
NS_LDAPOPERATION_CID)
NS_IMPL_ADDREF(nsLDAPOperation)
NS_IMPL_RELEASE(nsLDAPOperation)
NS_INTERFACE_MAP_BEGIN(nsLDAPOperation)
NS_INTERFACE_MAP_ENTRY(nsILDAPOperation)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsILDAPOperation)
NS_IMPL_QUERY_CLASSINFO(nsLDAPOperation)
NS_INTERFACE_MAP_END_THREADSAFE
NS_IMPL_CI_INTERFACE_GETTER(nsLDAPOperation, nsILDAPOperation)
/**
* Initializes this operation. Must be called prior to use.
*
* @param aConnection connection this operation should use
* @param aMessageListener where are the results are called back to.
*/
NS_IMETHODIMP
nsLDAPOperation::Init(nsILDAPConnection *aConnection,
nsILDAPMessageListener *aMessageListener,
nsISupports *aClosure)
{
if (!aConnection) {
return NS_ERROR_ILLEGAL_VALUE;
}
// so we know that the operation is not yet running (and therefore don't
// try and call ldap_abandon_ext() on it) or remove it from the queue.
//
mMsgID = 0;
// set the member vars
//
mConnection = static_cast<nsLDAPConnection*>(aConnection);
mMessageListener = aMessageListener;
mClosure = aClosure;
// cache the connection handle
//
mConnectionHandle =
mConnection->mConnectionHandle;
return NS_OK;
}
NS_IMETHODIMP
nsLDAPOperation::GetClosure(nsISupports **_retval)
{
if (!_retval) {
return NS_ERROR_ILLEGAL_VALUE;
}
NS_IF_ADDREF(*_retval = mClosure);
return NS_OK;
}
NS_IMETHODIMP
nsLDAPOperation::SetClosure(nsISupports *aClosure)
{
mClosure = aClosure;
return NS_OK;
}
NS_IMETHODIMP
nsLDAPOperation::GetConnection(nsILDAPConnection* *aConnection)
{
if (!aConnection) {
return NS_ERROR_ILLEGAL_VALUE;
}
*aConnection = mConnection;
NS_IF_ADDREF(*aConnection);
return NS_OK;
}
void
nsLDAPOperation::Clear()
{
mMessageListener = nullptr;
mClosure = nullptr;
mConnection = nullptr;
}
NS_IMETHODIMP
nsLDAPOperation::GetMessageListener(nsILDAPMessageListener **aMessageListener)
{
if (!aMessageListener) {
return NS_ERROR_ILLEGAL_VALUE;
}
*aMessageListener = mMessageListener;
NS_IF_ADDREF(*aMessageListener);
return NS_OK;
}
NS_IMETHODIMP
nsLDAPOperation::SaslBind(const nsACString &service,
const nsACString &mechanism,
nsIAuthModule *authModule)
{
nsresult rv;
nsAutoCString bindName;
struct berval creds;
unsigned int credlen;
mAuthModule = authModule;
mMechanism.Assign(mechanism);
rv = mConnection->GetBindName(bindName);
NS_ENSURE_SUCCESS(rv, rv);
creds.bv_val = NULL;
mAuthModule->Init(PromiseFlatCString(service).get(),
nsIAuthModule::REQ_DEFAULT, nullptr,
NS_ConvertUTF8toUTF16(bindName).get(), nullptr);
rv = mAuthModule->GetNextToken(nullptr, 0, (void **)&creds.bv_val,
&credlen);
if (NS_FAILED(rv) || !creds.bv_val)
return rv;
creds.bv_len = credlen;
const int lderrno = ldap_sasl_bind(mConnectionHandle, bindName.get(),
mMechanism.get(), &creds, NULL, NULL,
&mMsgID);
free(creds.bv_val);
if (lderrno != LDAP_SUCCESS)
return TranslateLDAPErrorToNSError(lderrno);
// make sure the connection knows where to call back once the messages
// for this operation start coming in
rv = mConnection->AddPendingOperation(mMsgID, this);
if (NS_FAILED(rv))
(void)ldap_abandon_ext(mConnectionHandle, mMsgID, 0, 0);
return rv;
}
NS_IMETHODIMP
nsLDAPOperation::SaslStep(const char *token, uint32_t tokenLen)
{
nsresult rv;
nsAutoCString bindName;
struct berval clientCreds;
struct berval serverCreds;
unsigned int credlen;
rv = mConnection->RemovePendingOperation(mMsgID);
NS_ENSURE_SUCCESS(rv, rv);
serverCreds.bv_val = (char *) token;
serverCreds.bv_len = tokenLen;
rv = mConnection->GetBindName(bindName);
NS_ENSURE_SUCCESS(rv, rv);
rv = mAuthModule->GetNextToken(serverCreds.bv_val, serverCreds.bv_len,
(void **) &clientCreds.bv_val, &credlen);
NS_ENSURE_SUCCESS(rv, rv);
clientCreds.bv_len = credlen;
const int lderrno = ldap_sasl_bind(mConnectionHandle, bindName.get(),
mMechanism.get(), &clientCreds, NULL,
NULL, &mMsgID);
free(clientCreds.bv_val);
if (lderrno != LDAP_SUCCESS)
return TranslateLDAPErrorToNSError(lderrno);
// make sure the connection knows where to call back once the messages
// for this operation start coming in
rv = mConnection->AddPendingOperation(mMsgID, this);
if (NS_FAILED(rv))
(void)ldap_abandon_ext(mConnectionHandle, mMsgID, 0, 0);
return rv;
}
// wrapper for ldap_simple_bind()
//
NS_IMETHODIMP
nsLDAPOperation::SimpleBind(const nsACString& passwd)
{
RefPtr<nsLDAPConnection> connection = mConnection;
// There is a possibilty that mConnection can be cleared by another
// thread. Grabbing a local reference to mConnection may avoid this.
// See https://bugzilla.mozilla.org/show_bug.cgi?id=557928#c1
nsresult rv;
nsAutoCString bindName;
int32_t originalMsgID = mMsgID;
// Ugly hack alert:
// the first time we get called with a passwd, remember it.
// Then, if we get called again w/o a password, use the
// saved one. Getting called again means we're trying to
// fall back to VERSION2.
// Since LDAP operations are thrown away when done, it won't stay
// around in memory.
if (!passwd.IsEmpty())
mSavePassword = passwd;
NS_PRECONDITION(mMessageListener, "MessageListener not set");
rv = connection->GetBindName(bindName);
if (NS_FAILED(rv))
return rv;
MOZ_LOG(gLDAPLogModule, mozilla::LogLevel::Debug,
("nsLDAPOperation::SimpleBind(): called; bindName = '%s'; ",
bindName.get()));
// this (nsLDAPOperation) may be released by RemovePendingOperation()
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1063829.
RefPtr<nsLDAPOperation> kungFuDeathGrip = this;
// If this is a second try at binding, remove the operation from pending ops
// because msg id has changed...
if (originalMsgID)
connection->RemovePendingOperation(originalMsgID);
mMsgID = ldap_simple_bind(mConnectionHandle, bindName.get(),
mSavePassword.get());
if (mMsgID == -1) {
// XXX Should NS_ERROR_LDAP_SERVER_DOWN cause a rebind here?
return TranslateLDAPErrorToNSError(ldap_get_lderrno(mConnectionHandle,
0, 0));
}
// make sure the connection knows where to call back once the messages
// for this operation start coming in
rv = connection->AddPendingOperation(mMsgID, this);
switch (rv) {
case NS_OK:
break;
// note that the return value of ldap_abandon_ext() is ignored, as
// there's nothing useful to do with it
case NS_ERROR_OUT_OF_MEMORY:
(void)ldap_abandon_ext(mConnectionHandle, mMsgID, 0, 0);
return NS_ERROR_OUT_OF_MEMORY;
break;
case NS_ERROR_UNEXPECTED:
case NS_ERROR_ILLEGAL_VALUE:
default:
(void)ldap_abandon_ext(mConnectionHandle, mMsgID, 0, 0);
return NS_ERROR_UNEXPECTED;
}
return NS_OK;
}
/**
* Given an nsIArray of nsILDAPControls, return the appropriate
* zero-terminated array of LDAPControls ready to pass in to the C SDK.
*/
static nsresult
convertControlArray(nsIArray *aXpcomArray, LDAPControl ***aArray)
{
// get the size of the original array
uint32_t length;
nsresult rv = aXpcomArray->GetLength(&length);
NS_ENSURE_SUCCESS(rv, rv);
// don't allocate an array if someone passed us in an empty one
if (!length) {
*aArray = 0;
return NS_OK;
}
// allocate a local array of the form understood by the C-SDK;
// +1 is to account for the final null terminator. PR_Calloc is
// is used so that ldap_controls_free will work anywhere during the
// iteration
LDAPControl **controls =
static_cast<LDAPControl **>
(PR_Calloc(length+1, sizeof(LDAPControl)));
// prepare to enumerate the array
nsCOMPtr<nsISimpleEnumerator> enumerator;
rv = aXpcomArray->Enumerate(getter_AddRefs(enumerator));
NS_ENSURE_SUCCESS(rv, rv);
bool moreElements;
rv = enumerator->HasMoreElements(&moreElements);
NS_ENSURE_SUCCESS(rv, rv);
uint32_t i = 0;
while (moreElements) {
// get the next array element
nsCOMPtr<nsISupports> isupports;
rv = enumerator->GetNext(getter_AddRefs(isupports));
if (NS_FAILED(rv)) {
ldap_controls_free(controls);
return rv;
}
nsCOMPtr<nsILDAPControl> control = do_QueryInterface(isupports, &rv);
if (NS_FAILED(rv)) {
ldap_controls_free(controls);
return NS_ERROR_INVALID_ARG; // bogus element in the array
}
nsLDAPControl *ctl = static_cast<nsLDAPControl *>
(static_cast<nsILDAPControl *>
(control.get()));
// convert it to an LDAPControl structure placed in the new array
rv = ctl->ToLDAPControl(&controls[i]);
if (NS_FAILED(rv)) {
ldap_controls_free(controls);
return rv;
}
// on to the next element
rv = enumerator->HasMoreElements(&moreElements);
if (NS_FAILED(rv)) {
ldap_controls_free(controls);
return NS_ERROR_UNEXPECTED;
}
++i;
}
*aArray = controls;
return NS_OK;
}
NS_IMETHODIMP
nsLDAPOperation::SearchExt(const nsACString& aBaseDn, int32_t aScope,
const nsACString& aFilter,
const nsACString &aAttributes,
PRIntervalTime aTimeOut, int32_t aSizeLimit)
{
if (!mMessageListener) {
NS_ERROR("nsLDAPOperation::SearchExt(): mMessageListener not set");
return NS_ERROR_NOT_INITIALIZED;
}
// XXX add control logging
MOZ_LOG(gLDAPLogModule, mozilla::LogLevel::Debug,
("nsLDAPOperation::SearchExt(): called with aBaseDn = '%s'; "
"aFilter = '%s'; aAttributes = %s; aSizeLimit = %d",
PromiseFlatCString(aBaseDn).get(),
PromiseFlatCString(aFilter).get(),
PromiseFlatCString(aAttributes).get(), aSizeLimit));
LDAPControl **serverctls = 0;
nsresult rv;
if (mServerControls) {
rv = convertControlArray(mServerControls, &serverctls);
if (NS_FAILED(rv)) {
MOZ_LOG(gLDAPLogModule, mozilla::LogLevel::Error,
("nsLDAPOperation::SearchExt(): error converting server "
"control array: %x", rv));
return rv;
}
}
LDAPControl **clientctls = 0;
if (mClientControls) {
rv = convertControlArray(mClientControls, &clientctls);
if (NS_FAILED(rv)) {
MOZ_LOG(gLDAPLogModule, mozilla::LogLevel::Error,
("nsLDAPOperation::SearchExt(): error converting client "
"control array: %x", rv));
ldap_controls_free(serverctls);
return rv;
}
}
// Convert our comma separated string to one that the C-SDK will like, i.e.
// convert to a char array and add a last NULL element.
nsTArray<nsCString> attrArray;
ParseString(aAttributes, ',', attrArray);
char **attrs = nullptr;
uint32_t origLength = attrArray.Length();
if (origLength)
{
attrs = static_cast<char **> (NS_Alloc((origLength + 1) * sizeof(char *)));
if (!attrs)
return NS_ERROR_OUT_OF_MEMORY;
for (uint32_t i = 0; i < origLength; ++i)
attrs[i] = ToNewCString(attrArray[i]);
attrs[origLength] = 0;
}
// XXX deal with timeout here
int retVal = ldap_search_ext(mConnectionHandle,
PromiseFlatCString(aBaseDn).get(),
aScope, PromiseFlatCString(aFilter).get(),
attrs, 0, serverctls, clientctls, 0,
aSizeLimit, &mMsgID);
// clean up
ldap_controls_free(serverctls);
ldap_controls_free(clientctls);
// The last entry is null, so no need to free that.
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(origLength, attrs);
rv = TranslateLDAPErrorToNSError(retVal);
NS_ENSURE_SUCCESS(rv, rv);
// make sure the connection knows where to call back once the messages
// for this operation start coming in
//
rv = mConnection->AddPendingOperation(mMsgID, this);
if (NS_FAILED(rv)) {
switch (rv) {
case NS_ERROR_OUT_OF_MEMORY:
(void)ldap_abandon_ext(mConnectionHandle, mMsgID, 0, 0);
return NS_ERROR_OUT_OF_MEMORY;
default:
(void)ldap_abandon_ext(mConnectionHandle, mMsgID, 0, 0);
NS_ERROR("nsLDAPOperation::SearchExt(): unexpected error in "
"mConnection->AddPendingOperation");
return NS_ERROR_UNEXPECTED;
}
}
return NS_OK;
}
NS_IMETHODIMP
nsLDAPOperation::GetMessageID(int32_t *aMsgID)
{
if (!aMsgID) {
return NS_ERROR_ILLEGAL_VALUE;
}
*aMsgID = mMsgID;
return NS_OK;
}
// as far as I can tell from reading the LDAP C SDK code, abandoning something
// that has already been abandoned does not return an error
//
NS_IMETHODIMP
nsLDAPOperation::AbandonExt()
{
nsresult rv;
nsresult retStatus = NS_OK;
if (!mMessageListener || mMsgID == 0) {
NS_ERROR("nsLDAPOperation::AbandonExt(): mMessageListener or "
"mMsgId not initialized");
return NS_ERROR_NOT_INITIALIZED;
}
// XXX handle controls here
if (mServerControls || mClientControls) {
return NS_ERROR_NOT_IMPLEMENTED;
}
rv = TranslateLDAPErrorToNSError(ldap_abandon_ext(mConnectionHandle,
mMsgID, 0, 0));
NS_ENSURE_SUCCESS(rv, rv);
// try to remove it from the pendingOperations queue, if it's there.
// even if something goes wrong here, the abandon() has already succeeded
// succeeded (and there's nothing else the caller can reasonably do),
// so we only pay attention to this in debug builds.
//
// check mConnection in case we're getting bit by
// http://bugzilla.mozilla.org/show_bug.cgi?id=239729, wherein we
// theorize that ::Clearing the operation is nulling out the mConnection
// from another thread.
if (mConnection)
{
rv = mConnection->RemovePendingOperation(mMsgID);
if (NS_FAILED(rv)) {
// XXXdmose should we keep AbandonExt from happening on multiple
// threads at the same time? that's when this condition is most
// likely to occur. i _think_ the LDAP C SDK is ok with this; need
// to verify.
//
NS_WARNING("nsLDAPOperation::AbandonExt: "
"mConnection->RemovePendingOperation(this) failed.");
}
}
return retStatus;
}
NS_IMETHODIMP
nsLDAPOperation::GetClientControls(nsIMutableArray **aControls)
{
NS_IF_ADDREF(*aControls = mClientControls);
return NS_OK;
}
NS_IMETHODIMP
nsLDAPOperation::SetClientControls(nsIMutableArray *aControls)
{
mClientControls = aControls;
return NS_OK;
}
NS_IMETHODIMP nsLDAPOperation::GetServerControls(nsIMutableArray **aControls)
{
NS_IF_ADDREF(*aControls = mServerControls);
return NS_OK;
}
NS_IMETHODIMP nsLDAPOperation::SetServerControls(nsIMutableArray *aControls)
{
mServerControls = aControls;
return NS_OK;
}
// wrappers for ldap_add_ext
//
nsresult
nsLDAPOperation::AddExt(const char *base,
nsIArray *mods,
LDAPControl **serverctrls,
LDAPControl **clientctrls)
{
if (!mMessageListener) {
NS_ERROR("nsLDAPOperation::AddExt(): mMessageListener not set");
return NS_ERROR_NOT_INITIALIZED;
}
LDAPMod **attrs = 0;
int retVal = LDAP_SUCCESS;
uint32_t modCount = 0;
nsresult rv = mods->GetLength(&modCount);
NS_ENSURE_SUCCESS(rv, rv);
if (mods && modCount) {
attrs = static_cast<LDAPMod **>(moz_xmalloc((modCount + 1) *
sizeof(LDAPMod *)));
if (!attrs) {
NS_ERROR("nsLDAPOperation::AddExt: out of memory ");
return NS_ERROR_OUT_OF_MEMORY;
}
nsAutoCString type;
uint32_t index;
for (index = 0; index < modCount && NS_SUCCEEDED(rv); ++index) {
attrs[index] = new LDAPMod();
if (!attrs[index])
return NS_ERROR_OUT_OF_MEMORY;
nsCOMPtr<nsILDAPModification> modif(do_QueryElementAt(mods, index, &rv));
if (NS_FAILED(rv))
break;
#ifdef NS_DEBUG
int32_t operation;
NS_ASSERTION(NS_SUCCEEDED(modif->GetOperation(&operation)) &&
((operation & ~LDAP_MOD_BVALUES) == LDAP_MOD_ADD),
"AddExt can only add.");
#endif
attrs[index]->mod_op = LDAP_MOD_ADD | LDAP_MOD_BVALUES;
nsresult rv = modif->GetType(type);
if (NS_FAILED(rv))
break;
attrs[index]->mod_type = ToNewCString(type);
rv = CopyValues(modif, &attrs[index]->mod_bvalues);
if (NS_FAILED(rv))
break;
}
if (NS_SUCCEEDED(rv)) {
attrs[modCount] = 0;
retVal = ldap_add_ext(mConnectionHandle, base, attrs,
serverctrls, clientctrls, &mMsgID);
}
else
// reset the modCount so we correctly free the array.
modCount = index;
}
for (uint32_t counter = 0; counter < modCount; ++counter)
delete attrs[counter];
free(attrs);
return NS_FAILED(rv) ? rv : TranslateLDAPErrorToNSError(retVal);
}
/**
* wrapper for ldap_add_ext(): kicks off an async add request.
*
* @param aBaseDn Base DN to search
* @param aModCount Number of modifications
* @param aMods Array of modifications
*
* XXX doesn't currently handle LDAPControl params
*
* void addExt (in AUTF8String aBaseDn, in unsigned long aModCount,
* [array, size_is (aModCount)] in nsILDAPModification aMods);
*/
NS_IMETHODIMP
nsLDAPOperation::AddExt(const nsACString& aBaseDn,
nsIArray *aMods)
{
MOZ_LOG(gLDAPLogModule, mozilla::LogLevel::Debug,
("nsLDAPOperation::AddExt(): called with aBaseDn = '%s'",
PromiseFlatCString(aBaseDn).get()));
nsresult rv = AddExt(PromiseFlatCString(aBaseDn).get(), aMods, 0, 0);
if (NS_FAILED(rv))
return rv;
// make sure the connection knows where to call back once the messages
// for this operation start coming in
rv = mConnection->AddPendingOperation(mMsgID, this);
if (NS_FAILED(rv)) {
(void)ldap_abandon_ext(mConnectionHandle, mMsgID, 0, 0);
MOZ_LOG(gLDAPLogModule, mozilla::LogLevel::Debug,
("nsLDAPOperation::AddExt(): abandoned due to rv %x",
rv));
}
return rv;
}
// wrappers for ldap_delete_ext
//
nsresult
nsLDAPOperation::DeleteExt(const char *base,
LDAPControl **serverctrls,
LDAPControl **clientctrls)
{
if (!mMessageListener) {
NS_ERROR("nsLDAPOperation::DeleteExt(): mMessageListener not set");
return NS_ERROR_NOT_INITIALIZED;
}
return TranslateLDAPErrorToNSError(ldap_delete_ext(mConnectionHandle, base,
serverctrls, clientctrls,
&mMsgID));
}
/**
* wrapper for ldap_delete_ext(): kicks off an async delete request.
*
* @param aBaseDn Base DN to delete
*
* XXX doesn't currently handle LDAPControl params
*
* void deleteExt(in AUTF8String aBaseDn);
*/
NS_IMETHODIMP
nsLDAPOperation::DeleteExt(const nsACString& aBaseDn)
{
MOZ_LOG(gLDAPLogModule, mozilla::LogLevel::Debug,
("nsLDAPOperation::DeleteExt(): called with aBaseDn = '%s'",
PromiseFlatCString(aBaseDn).get()));
nsresult rv = DeleteExt(PromiseFlatCString(aBaseDn).get(), 0, 0);
if (NS_FAILED(rv))
return rv;
// make sure the connection knows where to call back once the messages
// for this operation start coming in
rv = mConnection->AddPendingOperation(mMsgID, this);
if (NS_FAILED(rv)) {
(void)ldap_abandon_ext(mConnectionHandle, mMsgID, 0, 0);
MOZ_LOG(gLDAPLogModule, mozilla::LogLevel::Debug,
("nsLDAPOperation::AddExt(): abandoned due to rv %x",
rv));
}
return rv;
}
// wrappers for ldap_modify_ext
//
nsresult
nsLDAPOperation::ModifyExt(const char *base,
nsIArray *mods,
LDAPControl **serverctrls,
LDAPControl **clientctrls)
{
if (!mMessageListener) {
NS_ERROR("nsLDAPOperation::ModifyExt(): mMessageListener not set");
return NS_ERROR_NOT_INITIALIZED;
}
LDAPMod **attrs = 0;
int retVal = 0;
uint32_t modCount = 0;
nsresult rv = mods->GetLength(&modCount);
NS_ENSURE_SUCCESS(rv, rv);
if (modCount && mods) {
attrs = static_cast<LDAPMod **>(moz_xmalloc((modCount + 1) *
sizeof(LDAPMod *)));
if (!attrs) {
NS_ERROR("nsLDAPOperation::ModifyExt: out of memory ");
return NS_ERROR_OUT_OF_MEMORY;
}
nsAutoCString type;
uint32_t index;
for (index = 0; index < modCount && NS_SUCCEEDED(rv); ++index) {
attrs[index] = new LDAPMod();
if (!attrs[index])
return NS_ERROR_OUT_OF_MEMORY;
nsCOMPtr<nsILDAPModification> modif(do_QueryElementAt(mods, index, &rv));
if (NS_FAILED(rv))
break;
int32_t operation;
nsresult rv = modif->GetOperation(&operation);
if (NS_FAILED(rv))
break;
attrs[index]->mod_op = operation | LDAP_MOD_BVALUES;
rv = modif->GetType(type);
if (NS_FAILED(rv))
break;
attrs[index]->mod_type = ToNewCString(type);
rv = CopyValues(modif, &attrs[index]->mod_bvalues);
if (NS_FAILED(rv))
break;
}
if (NS_SUCCEEDED(rv)) {
attrs[modCount] = 0;
retVal = ldap_modify_ext(mConnectionHandle, base, attrs,
serverctrls, clientctrls, &mMsgID);
}
else
// reset the modCount so we correctly free the array.
modCount = index;
}
for (uint32_t counter = 0; counter < modCount; ++counter)
delete attrs[counter];
free(attrs);
return NS_FAILED(rv) ? rv : TranslateLDAPErrorToNSError(retVal);
}
/**
* wrapper for ldap_modify_ext(): kicks off an async modify request.
*
* @param aBaseDn Base DN to modify
* @param aModCount Number of modifications
* @param aMods Array of modifications
*
* XXX doesn't currently handle LDAPControl params
*
* void modifyExt (in AUTF8String aBaseDn, in unsigned long aModCount,
* [array, size_is (aModCount)] in nsILDAPModification aMods);
*/
NS_IMETHODIMP
nsLDAPOperation::ModifyExt(const nsACString& aBaseDn,
nsIArray *aMods)
{
MOZ_LOG(gLDAPLogModule, mozilla::LogLevel::Debug,
("nsLDAPOperation::ModifyExt(): called with aBaseDn = '%s'",
PromiseFlatCString(aBaseDn).get()));
nsresult rv = ModifyExt(PromiseFlatCString(aBaseDn).get(),
aMods, 0, 0);
if (NS_FAILED(rv))
return rv;
// make sure the connection knows where to call back once the messages
// for this operation start coming in
rv = mConnection->AddPendingOperation(mMsgID, this);
if (NS_FAILED(rv)) {
(void)ldap_abandon_ext(mConnectionHandle, mMsgID, 0, 0);
MOZ_LOG(gLDAPLogModule, mozilla::LogLevel::Debug,
("nsLDAPOperation::AddExt(): abandoned due to rv %x",
rv));
}
return rv;
}
// wrappers for ldap_rename
//
nsresult
nsLDAPOperation::Rename(const char *base,
const char *newRDn,
const char *newParent,
bool deleteOldRDn,
LDAPControl **serverctrls,
LDAPControl **clientctrls)
{
if (!mMessageListener) {
NS_ERROR("nsLDAPOperation::Rename(): mMessageListener not set");
return NS_ERROR_NOT_INITIALIZED;
}
return TranslateLDAPErrorToNSError(ldap_rename(mConnectionHandle, base,
newRDn, newParent,
deleteOldRDn, serverctrls,
clientctrls, &mMsgID));
}
/**
* wrapper for ldap_rename(): kicks off an async rename request.
*
* @param aBaseDn Base DN to rename
* @param aNewRDn New relative DN
* @param aNewParent DN of the new parent under which to move the
*
* XXX doesn't currently handle LDAPControl params
*
* void rename(in AUTF8String aBaseDn, in AUTF8String aNewRDn,
* in AUTF8String aNewParent, in boolean aDeleteOldRDn);
*/
NS_IMETHODIMP
nsLDAPOperation::Rename(const nsACString& aBaseDn,
const nsACString& aNewRDn,
const nsACString& aNewParent,
bool aDeleteOldRDn)
{
MOZ_LOG(gLDAPLogModule, mozilla::LogLevel::Debug,
("nsLDAPOperation::Rename(): called with aBaseDn = '%s'",
PromiseFlatCString(aBaseDn).get()));
nsresult rv = Rename(PromiseFlatCString(aBaseDn).get(),
PromiseFlatCString(aNewRDn).get(),
PromiseFlatCString(aNewParent).get(),
aDeleteOldRDn, 0, 0);
if (NS_FAILED(rv))
return rv;
// make sure the connection knows where to call back once the messages
// for this operation start coming in
rv = mConnection->AddPendingOperation(mMsgID, this);
if (NS_FAILED(rv)) {
(void)ldap_abandon_ext(mConnectionHandle, mMsgID, 0, 0);
MOZ_LOG(gLDAPLogModule, mozilla::LogLevel::Debug,
("nsLDAPOperation::AddExt(): abandoned due to rv %x",
rv));
}
return rv;
}
// wrappers for ldap_search_ext
//
/* static */
nsresult
nsLDAPOperation::CopyValues(nsILDAPModification* aMod, berval*** aBValues)
{
nsCOMPtr<nsIArray> values;
nsresult rv = aMod->GetValues(getter_AddRefs(values));
NS_ENSURE_SUCCESS(rv, rv);
uint32_t valuesCount;
rv = values->GetLength(&valuesCount);
NS_ENSURE_SUCCESS(rv, rv);
*aBValues = static_cast<berval **>
(moz_xmalloc((valuesCount + 1) *
sizeof(berval *)));
if (!*aBValues)
return NS_ERROR_OUT_OF_MEMORY;
uint32_t valueIndex;
for (valueIndex = 0; valueIndex < valuesCount; ++valueIndex) {
nsCOMPtr<nsILDAPBERValue> value(do_QueryElementAt(values, valueIndex, &rv));
berval* bval = new berval;
if (NS_FAILED(rv) || !bval) {
for (uint32_t counter = 0;
counter < valueIndex && counter < valuesCount;
++counter)
delete (*aBValues)[valueIndex];
free(*aBValues);
delete bval;
return NS_ERROR_OUT_OF_MEMORY;
}
value->Get((uint32_t*)&bval->bv_len,
(uint8_t**)&bval->bv_val);
(*aBValues)[valueIndex] = bval;
}
(*aBValues)[valuesCount] = 0;
return NS_OK;
}

View file

@ -0,0 +1,104 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _nsLDAPOperation_h_
#define _nsLDAPOperation_h_
#include "ldap.h"
#include "nsCOMPtr.h"
#include "nsILDAPConnection.h"
#include "nsILDAPOperation.h"
#include "nsILDAPMessageListener.h"
#include "nsStringGlue.h"
#include "nsIMutableArray.h"
#include "nsLDAPConnection.h"
// 97a479d0-9a44-47c6-a17a-87f9b00294bb
#define NS_LDAPOPERATION_CID \
{ 0x97a479d0, 0x9a44, 0x47c6, \
{ 0xa1, 0x7a, 0x87, 0xf9, 0xb0, 0x02, 0x94, 0xbb}}
class nsLDAPOperation : public nsILDAPOperation
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSILDAPOPERATION
// constructor & destructor
//
nsLDAPOperation();
/**
* used to break cycles
*/
void Clear();
private:
virtual ~nsLDAPOperation();
/**
* wrapper for ldap_add_ext()
*
* XXX should move to idl, once LDAPControls have an IDL representation
*/
nsresult AddExt(const char *base, // base DN to add
nsIArray *mods, // Array of modifications
LDAPControl **serverctrls,
LDAPControl **clientctrls);
/**
* wrapper for ldap_delete_ext()
*
* XXX should move to idl, once LDAPControls have an IDL representation
*/
nsresult DeleteExt(const char *base, // base DN to delete
LDAPControl **serverctrls,
LDAPControl **clientctrls);
/**
* wrapper for ldap_modify_ext()
*
* XXX should move to idl, once LDAPControls have an IDL representation
*/
nsresult ModifyExt(const char *base, // base DN to modify
nsIArray *mods, // array of modifications
LDAPControl **serverctrls,
LDAPControl **clientctrls);
/**
* wrapper for ldap_rename()
*
* XXX should move to idl, once LDAPControls have an IDL representation
*/
nsresult Rename(const char *base, // base DN to rename
const char *newRDn, // new RDN
const char *newParent, // DN of the new parent
bool deleteOldRDn, // remove old RDN in the entry?
LDAPControl **serverctrls,
LDAPControl **clientctrls);
/**
* Helper function to copy the values of an nsILDAPModification into an
* array of berval's.
*/
static nsresult CopyValues(nsILDAPModification* aMod, berval*** aBValues);
nsCOMPtr<nsILDAPMessageListener> mMessageListener; // results go here
nsCOMPtr<nsISupports> mClosure; // private parameter (anything caller desires)
RefPtr<nsLDAPConnection> mConnection; // connection this op is on
LDAP *mConnectionHandle; // cache connection handle
nsCString mSavePassword;
nsCString mMechanism;
nsCOMPtr<nsIAuthModule> mAuthModule;
int32_t mMsgID; // opaque handle to outbound message for this op
nsCOMPtr<nsIMutableArray> mClientControls;
nsCOMPtr<nsIMutableArray> mServerControls;
};
#endif // _nsLDAPOperation_h

View file

@ -0,0 +1,62 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
const kNetworkProtocolCIDPrefix = "@mozilla.org/network/protocol;1?name=";
const nsIProtocolHandler = Components.interfaces.nsIProtocolHandler;
function makeProtocolHandler(aCID, aProtocol, aDefaultPort) {
return {
classID: Components.ID(aCID),
QueryInterface: XPCOMUtils.generateQI([nsIProtocolHandler]),
scheme: aProtocol,
defaultPort: aDefaultPort,
protocolFlags: nsIProtocolHandler.URI_NORELATIVE |
nsIProtocolHandler.URI_DANGEROUS_TO_LOAD |
nsIProtocolHandler.ALLOWS_PROXY,
newURI: function (aSpec, aOriginCharset, aBaseURI) {
var url = Components.classes["@mozilla.org/network/ldap-url;1"]
.createInstance(Components.interfaces.nsIURI);
if (url instanceof Components.interfaces.nsILDAPURL)
url.init(Components.interfaces.nsIStandardURL.URLTYPE_STANDARD,
aDefaultPort, aSpec, aOriginCharset, aBaseURI);
return url;
},
newChannel: function (aURI) {
return this.newChannel2(aURI, null);
},
newChannel2: function (aURI, aLoadInfo) {
if ("@mozilla.org/network/ldap-channel;1" in Components.classes) {
var channel = Components.classes["@mozilla.org/network/ldap-channel;1"]
.createInstance(Components.interfaces.nsIChannel);
channel.init(aURI);
return channel;
}
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
},
allowPort: function (port, scheme) {
return port == aDefaultPort;
}
};
}
function nsLDAPProtocolHandler() {}
nsLDAPProtocolHandler.prototype = makeProtocolHandler("{b3de9249-b0e5-4c12-8d91-c9a434fd80f5}", "ldap", 389);
function nsLDAPSProtocolHandler() {}
nsLDAPSProtocolHandler.prototype = makeProtocolHandler("{c85a5ef2-9c56-445f-b029-76889f2dd29b}", "ldaps", 636);
const NSGetFactory = XPCOMUtils.generateNSGetFactory([nsLDAPProtocolHandler,
nsLDAPSProtocolHandler]);

View file

@ -0,0 +1,147 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsIClassInfoImpl.h"
#include "mozilla/ModuleUtils.h"
#include "nsLDAPInternal.h"
#include "nsLDAPURL.h"
#include "nsLDAPConnection.h"
#include "nsLDAPOperation.h"
#include "nsLDAPMessage.h"
#include "nsLDAPModification.h"
#include "nsLDAPServer.h"
#include "nsLDAPService.h"
#include "nsLDAPBERValue.h"
#include "nsLDAPBERElement.h"
#include "nsLDAPControl.h"
#ifdef MOZ_PREF_EXTENSIONS
#include "nsLDAPSyncQuery.h"
#endif
#include "ldappr.h"
#include "mozilla/Logging.h"
// use the default constructor
//
NS_GENERIC_FACTORY_CONSTRUCTOR(nsLDAPConnection)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsLDAPOperation)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsLDAPMessage)
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsLDAPModification, Init)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsLDAPServer)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsLDAPURL)
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsLDAPService, Init)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsLDAPBERValue)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsLDAPBERElement)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsLDAPControl)
#ifdef MOZ_PREF_EXTENSIONS
NS_GENERIC_FACTORY_CONSTRUCTOR(nsLDAPSyncQuery)
#endif
NS_DEFINE_NAMED_CID(NS_LDAPCONNECTION_CID);
NS_DEFINE_NAMED_CID(NS_LDAPOPERATION_CID);
NS_DEFINE_NAMED_CID(NS_LDAPMESSAGE_CID);
NS_DEFINE_NAMED_CID(NS_LDAPMODIFICATION_CID);
NS_DEFINE_NAMED_CID(NS_LDAPSERVER_CID);
NS_DEFINE_NAMED_CID(NS_LDAPSERVICE_CID);
NS_DEFINE_NAMED_CID(NS_LDAPURL_CID);
NS_DEFINE_NAMED_CID(NS_LDAPBERVALUE_CID);
NS_DEFINE_NAMED_CID(NS_LDAPBERELEMENT_CID);
#ifdef MOZ_PREF_EXTENSIONS
NS_DEFINE_NAMED_CID(NS_LDAPSYNCQUERY_CID);
#endif
NS_DEFINE_NAMED_CID(NS_LDAPCONTROL_CID);
// a table of the CIDs implemented by this module
//
const mozilla::Module::CIDEntry kLDAPProtocolCIDs[] = {
{ &kNS_LDAPCONNECTION_CID, false, NULL, nsLDAPConnectionConstructor},
{ &kNS_LDAPOPERATION_CID, false, NULL, nsLDAPOperationConstructor},
{ &kNS_LDAPMESSAGE_CID, false, NULL, nsLDAPMessageConstructor},
{ &kNS_LDAPMODIFICATION_CID, false, NULL, nsLDAPModificationConstructor},
{ &kNS_LDAPSERVER_CID, false, NULL, nsLDAPServerConstructor},
{ &kNS_LDAPSERVICE_CID, false, NULL, nsLDAPServiceConstructor},
{ &kNS_LDAPURL_CID, false, NULL, nsLDAPURLConstructor},
{ &kNS_LDAPBERVALUE_CID, false, NULL, nsLDAPBERValueConstructor},
{ &kNS_LDAPBERELEMENT_CID, false, NULL, nsLDAPBERElementConstructor},
#ifdef MOZ_PREF_EXTENSIONS
{ &kNS_LDAPSYNCQUERY_CID, false, NULL, nsLDAPSyncQueryConstructor},
#endif
{ &kNS_LDAPCONTROL_CID, false, NULL, nsLDAPControlConstructor},
{ NULL }
};
const mozilla::Module::ContractIDEntry kLDAPProtocolContracts[] = {
{ "@mozilla.org/network/ldap-connection;1", &kNS_LDAPCONNECTION_CID},
{ "@mozilla.org/network/ldap-operation;1", &kNS_LDAPOPERATION_CID},
{ "@mozilla.org/network/ldap-message;1", &kNS_LDAPMESSAGE_CID},
{ "@mozilla.org/network/ldap-modification;1", &kNS_LDAPMODIFICATION_CID},
{ "@mozilla.org/network/ldap-server;1", &kNS_LDAPSERVER_CID},
{ "@mozilla.org/network/ldap-service;1", &kNS_LDAPSERVICE_CID},
{ "@mozilla.org/network/ldap-url;1", &kNS_LDAPURL_CID},
{ "@mozilla.org/network/ldap-ber-value;1", &kNS_LDAPBERVALUE_CID},
{ "@mozilla.org/network/ldap-ber-element;1", &kNS_LDAPBERELEMENT_CID},
#ifdef MOZ_PREF_EXTENSIONS
{ "@mozilla.org/ldapsyncquery;1", &kNS_LDAPSYNCQUERY_CID},
#endif
{ "@mozilla.org/network/ldap-control;1", &kNS_LDAPCONTROL_CID},
{ NULL }
};
static nsresult
nsLDAPInitialize()
{
#ifdef PR_LOGGING
gLDAPLogModule = PR_NewLogModule("ldap");
if (!gLDAPLogModule) {
PR_fprintf(PR_STDERR,
"nsLDAP_Initialize(): PR_NewLogModule() failed\n");
return NS_ERROR_NOT_AVAILABLE;
}
#endif
// use NSPR under the hood for all networking
//
int rv = prldap_install_routines( NULL, 1 /* shared */ );
if (rv != LDAP_SUCCESS) {
MOZ_LOG(gLDAPLogModule, mozilla::LogLevel::Error,
("nsLDAPInitialize(): pr_ldap_install_routines() failed: %s\n",
ldap_err2string(rv)));
return NS_ERROR_FAILURE;
}
// Never block for more than 10000 milliseconds (ie 10 seconds) doing any
// sort of I/O operation.
//
rv = prldap_set_session_option(0, 0, PRLDAP_OPT_IO_MAX_TIMEOUT,
10000);
if (rv != LDAP_SUCCESS) {
MOZ_LOG(gLDAPLogModule, mozilla::LogLevel::Error,
("nsLDAPInitialize(): error setting PRLDAP_OPT_IO_MAX_TIMEOUT:"
" %s\n", ldap_err2string(rv)));
return NS_ERROR_FAILURE;
}
return NS_OK;
}
static const mozilla::Module kLDAPProtocolModule = {
mozilla::Module::kVersion,
kLDAPProtocolCIDs,
kLDAPProtocolContracts,
NULL,
NULL,
nsLDAPInitialize,
NULL
};
NSMODULE_DEFN(nsLDAPProtocolModule) = &kLDAPProtocolModule;
#ifdef PR_LOGGING
PRLogModuleInfo *gLDAPLogModule = 0;
#endif

View file

@ -0,0 +1,342 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// Only build this code if PSM is being built also
//
#include "nsLDAPInternal.h"
#include "nsCOMPtr.h"
#include "nsIServiceManager.h"
#include "nsIInterfaceRequestor.h"
#include "nsNetCID.h"
#include "nsISocketProvider.h"
#include "nsISSLSocketControl.h"
#include "nsString.h"
#include "nsMemory.h"
#include "plstr.h"
#include "ldap.h"
#include "ldappr.h"
#include "nsComponentManagerUtils.h"
#include "nsServiceManagerUtils.h"
// LDAP per-session data structure.
//
typedef struct {
char *hostname;
LDAP_X_EXTIOF_CLOSE_CALLBACK *realClose;
LDAP_X_EXTIOF_CONNECT_CALLBACK *realConnect;
LDAP_X_EXTIOF_DISPOSEHANDLE_CALLBACK *realDisposeHandle;
} nsLDAPSSLSessionClosure;
// LDAP per-socket data structure.
//
typedef struct {
nsLDAPSSLSessionClosure *sessionClosure; /* session info */
} nsLDAPSSLSocketClosure;
// free the per-socket data structure as necessary
//
static void
nsLDAPSSLFreeSocketClosure(nsLDAPSSLSocketClosure **aClosure)
{
if (aClosure && *aClosure) {
free(*aClosure);
*aClosure = nullptr;
}
}
// Replacement close() function, which cleans up local stuff associated
// with this socket, and then calls the real close function.
//
extern "C" int LDAP_CALLBACK
nsLDAPSSLClose(int s, struct lextiof_socket_private *socketarg)
{
PRLDAPSocketInfo socketInfo;
nsLDAPSSLSocketClosure *socketClosure;
nsLDAPSSLSessionClosure *sessionClosure;
// get the socketInfo associated with this socket
//
memset(&socketInfo, 0, sizeof(socketInfo));
socketInfo.soinfo_size = PRLDAP_SOCKETINFO_SIZE;
if (prldap_get_socket_info(s, socketarg, &socketInfo) != LDAP_SUCCESS) {
NS_ERROR("nsLDAPSSLClose(): prldap_get_socket_info() failed\n");
return -1;
}
// save off the session closure data in an automatic, since we're going to
// need to call through it
//
socketClosure = reinterpret_cast<nsLDAPSSLSocketClosure *>
(socketInfo.soinfo_appdata);
sessionClosure = socketClosure->sessionClosure;
// free the socket closure data
//
nsLDAPSSLFreeSocketClosure(
reinterpret_cast<nsLDAPSSLSocketClosure **>
(&socketInfo.soinfo_appdata));
// call the real close function
//
return (*(sessionClosure->realClose))(s, socketarg);
}
// Replacement connection function. Calls the real connect function,
//
extern "C" int LDAP_CALLBACK
nsLDAPSSLConnect(const char *hostlist, int defport, int timeout,
unsigned long options,
struct lextiof_session_private *sessionarg,
struct lextiof_socket_private **socketargp )
{
PRLDAPSocketInfo socketInfo;
PRLDAPSessionInfo sessionInfo;
nsLDAPSSLSocketClosure *socketClosure = nullptr;
nsLDAPSSLSessionClosure *sessionClosure;
int intfd = -1;
nsCOMPtr <nsISupports> securityInfo;
nsCOMPtr <nsISocketProvider> tlsSocketProvider;
nsCOMPtr <nsISSLSocketControl> sslSocketControl;
nsresult rv;
// Ensure secure option is set. Also, clear secure bit in options
// the we pass to the standard connect() function (since it doesn't know
// how to handle the secure option).
//
NS_ASSERTION(options & LDAP_X_EXTIOF_OPT_SECURE,
"nsLDAPSSLConnect(): called for non-secure connection");
options &= ~LDAP_X_EXTIOF_OPT_SECURE;
// Retrieve session info. so we can store a pointer to our session info.
// in our socket info. later.
//
memset(&sessionInfo, 0, sizeof(sessionInfo));
sessionInfo.seinfo_size = PRLDAP_SESSIONINFO_SIZE;
if (prldap_get_session_info(nullptr, sessionarg, &sessionInfo)
!= LDAP_SUCCESS) {
NS_ERROR("nsLDAPSSLConnect(): unable to get session info");
return -1;
}
sessionClosure = reinterpret_cast<nsLDAPSSLSessionClosure *>
(sessionInfo.seinfo_appdata);
// Call the real connect() callback to make the TCP connection. If it
// succeeds, *socketargp is set.
//
intfd = (*(sessionClosure->realConnect))(hostlist, defport, timeout,
options, sessionarg, socketargp);
if ( intfd < 0 ) {
PR_LOG(gLDAPLogModule, PR_LOG_DEBUG,
("nsLDAPSSLConnect(): standard connect() function returned %d",
intfd));
return intfd;
}
// Retrieve socket info from the newly created socket so that we
// have the PRFileDesc onto which we will be layering SSL.
//
memset(&socketInfo, 0, sizeof(socketInfo));
socketInfo.soinfo_size = PRLDAP_SOCKETINFO_SIZE;
if (prldap_get_socket_info(intfd, *socketargp, &socketInfo)
!= LDAP_SUCCESS) {
NS_ERROR("nsLDAPSSLConnect(): unable to get socket info");
goto close_socket_and_exit_with_error;
}
// Allocate a structure to hold our socket-specific data.
//
socketClosure = static_cast<nsLDAPSSLSocketClosure *>(moz_xmalloc(
sizeof(nsLDAPSSLSocketClosure)));
if (!socketClosure) {
NS_WARNING("nsLDAPSSLConnect(): unable to allocate socket closure");
goto close_socket_and_exit_with_error;
}
memset(socketClosure, 0, sizeof(nsLDAPSSLSocketClosure));
socketClosure->sessionClosure = sessionClosure;
// Add the NSPR layer for SSL provided by PSM to this socket.
//
tlsSocketProvider = do_GetService(NS_STARTTLSSOCKETPROVIDER_CONTRACTID,
&rv);
if (NS_FAILED(rv)) {
NS_ERROR("nsLDAPSSLConnect(): unable to get socket provider service");
goto close_socket_and_exit_with_error;
}
// XXXdmose: Note that hostlist can be a list of hosts (in the
// current XPCOM SDK code, it will always be a list of IP
// addresses). Because of this, we need to use
// sessionClosure->hostname which was passed in separately to tell
// AddToSocket what to match the name in the certificate against.
// What exactly happen will happen when this is used with some IP
// address in the list other than the first one is not entirely
// clear, and I suspect it may depend on the format of the name in
// the certificate. Need to investigate.
//
rv = tlsSocketProvider->AddToSocket(PR_AF_INET,
sessionClosure->hostname,
defport,
nullptr,
mozilla::NeckoOriginAttributes(),
0,
socketInfo.soinfo_prfd,
getter_AddRefs(securityInfo));
if (NS_FAILED(rv)) {
NS_ERROR("nsLDAPSSLConnect(): unable to add SSL layer to socket");
goto close_socket_and_exit_with_error;
}
// If possible we want to avoid using SSLv2, as this can confuse
// some directory servers (notably the netscape 4.1 ds). The only
// way that PSM provides for us to do this is to use a socket that can
// be used for the STARTTLS protocol, because the STARTTLS protocol disallows
// the use of SSLv2.
// (Thanks to Brian Ryner for helping figure this out).
//
sslSocketControl = do_QueryInterface(securityInfo, &rv);
if (NS_FAILED(rv)) {
NS_WARNING("nsLDAPSSLConnect(): unable to QI to nsISSLSocketControl");
} else {
rv = sslSocketControl->StartTLS();
if (NS_FAILED(rv)) {
NS_WARNING("nsLDAPSSLConnect(): StartTLS failed");
}
}
// Attach our closure to the socketInfo.
//
socketInfo.soinfo_appdata = reinterpret_cast<prldap_socket_private *>
(socketClosure);
if (prldap_set_socket_info(intfd, *socketargp, &socketInfo)
!= LDAP_SUCCESS ) {
NS_ERROR("nsLDAPSSLConnect(): unable to set socket info");
}
return intfd; // success
close_socket_and_exit_with_error:
if (socketInfo.soinfo_prfd) {
PR_Close(socketInfo.soinfo_prfd);
}
if (socketClosure) {
nsLDAPSSLFreeSocketClosure(&socketClosure);
}
if ( intfd >= 0 && *socketargp ) {
(*(sessionClosure->realClose))(intfd, *socketargp);
}
return -1;
}
// Free data associated with this session (LDAP *) as necessary.
//
static void
nsLDAPSSLFreeSessionClosure(nsLDAPSSLSessionClosure **aSessionClosure)
{
if (aSessionClosure && *aSessionClosure) {
// free the hostname
//
if ( (*aSessionClosure)->hostname ) {
PL_strfree((*aSessionClosure)->hostname);
(*aSessionClosure)->hostname = nullptr;
}
// free the structure itself
//
free(*aSessionClosure);
*aSessionClosure = nullptr;
}
}
// Replacement session handle disposal code. First cleans up our local
// stuff, then calls the original session handle disposal function.
//
extern "C" void LDAP_CALLBACK
nsLDAPSSLDisposeHandle(LDAP *ld, struct lextiof_session_private *sessionarg)
{
PRLDAPSessionInfo sessionInfo;
nsLDAPSSLSessionClosure *sessionClosure;
LDAP_X_EXTIOF_DISPOSEHANDLE_CALLBACK *disposehdl_fn;
memset(&sessionInfo, 0, sizeof(sessionInfo));
sessionInfo.seinfo_size = PRLDAP_SESSIONINFO_SIZE;
if (prldap_get_session_info(ld, nullptr, &sessionInfo) == LDAP_SUCCESS) {
sessionClosure = reinterpret_cast<nsLDAPSSLSessionClosure *>
(sessionInfo.seinfo_appdata);
disposehdl_fn = sessionClosure->realDisposeHandle;
nsLDAPSSLFreeSessionClosure(&sessionClosure);
(*disposehdl_fn)(ld, sessionarg);
}
}
// Installs appropriate routines and data for making this connection
// handle SSL. The aHostName is ultimately passed to PSM and is used to
// validate certificates.
//
nsresult
nsLDAPInstallSSL( LDAP *ld, const char *aHostName)
{
struct ldap_x_ext_io_fns iofns;
nsLDAPSSLSessionClosure *sessionClosure;
PRLDAPSessionInfo sessionInfo;
// Allocate our own session information.
//
sessionClosure = static_cast<nsLDAPSSLSessionClosure *>(moz_xmalloc(
sizeof(nsLDAPSSLSessionClosure)));
if (!sessionClosure) {
return NS_ERROR_OUT_OF_MEMORY;
}
memset(sessionClosure, 0, sizeof(nsLDAPSSLSessionClosure));
// Override a few functions, saving a pointer to the original function
// in each case so we can call it from our SSL savvy functions.
//
memset(&iofns, 0, sizeof(iofns));
iofns.lextiof_size = LDAP_X_EXTIO_FNS_SIZE;
if (ldap_get_option(ld, LDAP_X_OPT_EXTIO_FN_PTRS,
static_cast<void *>(&iofns)) != LDAP_SUCCESS) {
NS_ERROR("nsLDAPInstallSSL(): unexpected error getting"
" LDAP_X_OPT_EXTIO_FN_PTRS");
nsLDAPSSLFreeSessionClosure(&sessionClosure);
return NS_ERROR_UNEXPECTED;
}
// Make a copy of the hostname to pass to AddToSocket later
//
sessionClosure->hostname = PL_strdup(aHostName);
if (!sessionClosure->hostname) {
NS_ERROR("nsLDAPInstallSSL(): PL_strdup failed\n");
nsLDAPSSLFreeSessionClosure(&sessionClosure);
return NS_ERROR_OUT_OF_MEMORY;
}
// Override functions
//
sessionClosure->realClose = iofns.lextiof_close;
iofns.lextiof_close = nsLDAPSSLClose;
sessionClosure->realConnect = iofns.lextiof_connect;
iofns.lextiof_connect = nsLDAPSSLConnect;
sessionClosure->realDisposeHandle = iofns.lextiof_disposehandle;
iofns.lextiof_disposehandle = nsLDAPSSLDisposeHandle;
if (ldap_set_option(ld, LDAP_X_OPT_EXTIO_FN_PTRS,
static_cast<void *>(&iofns)) != LDAP_SUCCESS) {
NS_ERROR("nsLDAPInstallSSL(): error setting LDAP_X_OPT_EXTIO_FN_PTRS");
nsLDAPSSLFreeSessionClosure(&sessionClosure);
return NS_ERROR_FAILURE;
}
// Store session info. for later retrieval.
//
sessionInfo.seinfo_size = PRLDAP_SESSIONINFO_SIZE;
sessionInfo.seinfo_appdata = reinterpret_cast<prldap_session_private *>
(sessionClosure);
if (prldap_set_session_info(ld, nullptr, &sessionInfo) != LDAP_SUCCESS) {
NS_ERROR("nsLDAPInstallSSL(): error setting prldap session info");
free(sessionClosure);
return NS_ERROR_UNEXPECTED;
}
return NS_OK;
}

View file

@ -0,0 +1,133 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsLDAPServer.h"
NS_IMPL_ISUPPORTS(nsLDAPServer, nsILDAPServer)
nsLDAPServer::nsLDAPServer()
: mSizeLimit(0),
mProtocolVersion(nsILDAPConnection::VERSION3)
{
}
nsLDAPServer::~nsLDAPServer()
{
}
// attribute wstring key;
NS_IMETHODIMP nsLDAPServer::GetKey(char16_t **_retval)
{
if (!_retval) {
NS_ERROR("nsLDAPServer::GetKey: null pointer ");
return NS_ERROR_NULL_POINTER;
}
*_retval = ToNewUnicode(mKey);
if (!*_retval) {
return NS_ERROR_OUT_OF_MEMORY;
}
return NS_OK;
}
NS_IMETHODIMP nsLDAPServer::SetKey(const char16_t *aKey)
{
mKey = aKey;
return NS_OK;
}
// attribute AUTF8String username;
NS_IMETHODIMP nsLDAPServer::GetUsername(nsACString& _retval)
{
_retval.Assign(mUsername);
return NS_OK;
}
NS_IMETHODIMP nsLDAPServer::SetUsername(const nsACString& aUsername)
{
mUsername.Assign(aUsername);
return NS_OK;
}
// attribute AUTF8String password;
NS_IMETHODIMP nsLDAPServer::GetPassword(nsACString& _retval)
{
_retval.Assign(mPassword);
return NS_OK;
}
NS_IMETHODIMP nsLDAPServer::SetPassword(const nsACString& aPassword)
{
mPassword.Assign(aPassword);
return NS_OK;
}
// attribute AUTF8String binddn;
NS_IMETHODIMP nsLDAPServer::GetBinddn(nsACString& _retval)
{
_retval.Assign(mBindDN);
return NS_OK;
}
NS_IMETHODIMP nsLDAPServer::SetBinddn(const nsACString& aBindDN)
{
mBindDN.Assign(aBindDN);
return NS_OK;
}
// attribute unsigned long sizelimit;
NS_IMETHODIMP nsLDAPServer::GetSizelimit(uint32_t *_retval)
{
if (!_retval) {
NS_ERROR("nsLDAPServer::GetSizelimit: null pointer ");
return NS_ERROR_NULL_POINTER;
}
*_retval = mSizeLimit;
return NS_OK;
}
NS_IMETHODIMP nsLDAPServer::SetSizelimit(uint32_t aSizeLimit)
{
mSizeLimit = aSizeLimit;
return NS_OK;
}
// attribute nsILDAPURL url;
NS_IMETHODIMP nsLDAPServer::GetUrl(nsILDAPURL **_retval)
{
if (!_retval) {
NS_ERROR("nsLDAPServer::GetUrl: null pointer ");
return NS_ERROR_NULL_POINTER;
}
NS_IF_ADDREF(*_retval = mURL);
return NS_OK;
}
NS_IMETHODIMP nsLDAPServer::SetUrl(nsILDAPURL *aURL)
{
mURL = aURL;
return NS_OK;
}
// attribute long protocolVersion
NS_IMETHODIMP nsLDAPServer::GetProtocolVersion(uint32_t *_retval)
{
if (!_retval) {
NS_ERROR("nsLDAPServer::GetProtocolVersion: null pointer ");
return NS_ERROR_NULL_POINTER;
}
*_retval = mProtocolVersion;
return NS_OK;
}
NS_IMETHODIMP nsLDAPServer::SetProtocolVersion(uint32_t aVersion)
{
if (aVersion != nsILDAPConnection::VERSION2 &&
aVersion != nsILDAPConnection::VERSION3) {
NS_ERROR("nsLDAPServer::SetProtocolVersion: invalid version");
return NS_ERROR_INVALID_ARG;
}
mProtocolVersion = aVersion;
return NS_OK;
}

View file

@ -0,0 +1,39 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsCOMPtr.h"
#include "nsStringGlue.h"
#include "nsILDAPServer.h"
#include "nsILDAPURL.h"
// 8bbbaa54-f316-4271-87c3-d52b5b1c1f5b
#define NS_LDAPSERVER_CID \
{ 0x8bbbaa54, 0xf316, 0x4271, \
{ 0x87, 0xc3, 0xd5, 0x2b, 0x5b, 0x1c, 0x1f, 0x5b}}
class nsLDAPServer : public nsILDAPServer
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSILDAPSERVER
// Constructor & destructor
//
nsLDAPServer();
protected:
virtual ~nsLDAPServer();
nsString mKey; // Unique identifier for this server object
nsCString mUsername; // Username / UID
nsCString mPassword; // Password to bind with
nsCString mBindDN; // DN associated with the UID above
uint32_t mSizeLimit; // Limit the LDAP search to this # of entries
uint32_t mProtocolVersion; // What version of LDAP to use?
// This "links" to a LDAP URL object, which holds further information
// related to the LDAP server. Like Host, port, base-DN and scope.
nsCOMPtr<nsILDAPURL> mURL;
};

View file

@ -0,0 +1,985 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsLDAPInternal.h"
#include "nsLDAPService.h"
#include "nsLDAPConnection.h"
#include "nsLDAPOperation.h"
#include "nsIServiceManager.h"
#include "nsIConsoleService.h"
#include "nsILDAPURL.h"
#include "nsMemory.h"
#include "nsILDAPErrors.h"
#include "nsComponentManagerUtils.h"
#include "nsServiceManagerUtils.h"
#include "mozilla/Logging.h"
using namespace mozilla;
// Constants for CIDs used here.
//
static NS_DEFINE_CID(kLDAPConnectionCID, NS_LDAPCONNECTION_CID);
static NS_DEFINE_CID(kLDAPOperationCID, NS_LDAPOPERATION_CID);
// First we provide all the methods for the "local" class
// nsLDAPServiceEntry.
//
// constructor
//
nsLDAPServiceEntry::nsLDAPServiceEntry()
: mLeases(0),
mTimestamp(0),
mDelete(false),
mRebinding(false)
{
}
// Init function
//
bool nsLDAPServiceEntry::Init()
{
return true;
}
// Set/Get the timestamp when this server was last used. We might have
// to use an "interval" here instead, see Bug #76887.
//
PRTime nsLDAPServiceEntry::GetTimestamp()
{
return mTimestamp;
}
void nsLDAPServiceEntry::SetTimestamp()
{
mTimestamp = PR_Now();
}
// Increment, decrement and Get the leases. This code might go away
// with bug #75954.
//
void nsLDAPServiceEntry::IncrementLeases()
{
mLeases++;
}
bool nsLDAPServiceEntry::DecrementLeases()
{
if (!mLeases) {
return false;
}
mLeases--;
return true;
}
uint32_t nsLDAPServiceEntry::GetLeases()
{
return mLeases;
}
// Get/Set the nsLDAPServer object for this entry.
//
already_AddRefed<nsILDAPServer> nsLDAPServiceEntry::GetServer()
{
nsCOMPtr<nsILDAPServer> server = mServer;
return server.forget();
}
bool nsLDAPServiceEntry::SetServer(nsILDAPServer *aServer)
{
if (!aServer) {
return false;
}
mServer = aServer;
return true;
}
// Get/Set/Clear the nsLDAPConnection object for this entry.
//
already_AddRefed<nsILDAPConnection> nsLDAPServiceEntry::GetConnection()
{
nsCOMPtr<nsILDAPConnection> conn = mConnection;
return conn.forget();
}
void nsLDAPServiceEntry::SetConnection(nsILDAPConnection *aConnection)
{
mConnection = aConnection;
}
// Get/Set the nsLDAPMessage object for this entry (it's a "cache").
//
already_AddRefed<nsILDAPMessage> nsLDAPServiceEntry::GetMessage()
{
nsCOMPtr<nsILDAPMessage> message = mMessage;
return message.forget();
}
void nsLDAPServiceEntry::SetMessage(nsILDAPMessage *aMessage)
{
mMessage = aMessage;
}
// Push/Pop pending listeners/callback for this server entry. This is
// implemented as a "stack" on top of the nsCOMArray, since we can
// potentially have more than one listener waiting for the connection
// to be available for consumption.
//
already_AddRefed<nsILDAPMessageListener> nsLDAPServiceEntry::PopListener()
{
if (mListeners.IsEmpty()) {
return 0;
}
nsCOMPtr<nsILDAPMessageListener> listener = mListeners[0];
mListeners.RemoveObjectAt(0);
return listener.forget();
}
bool nsLDAPServiceEntry::PushListener(nsILDAPMessageListener *listener)
{
return mListeners.AppendObject(listener);
}
// Mark this server to currently be rebinding. This is to avoid a
// race condition where multiple consumers could potentially request
// to reconnect the connection.
//
bool nsLDAPServiceEntry::IsRebinding()
{
return mRebinding;
}
void nsLDAPServiceEntry::SetRebinding(bool aState)
{
mRebinding = aState;
}
// Mark a service entry for deletion, this is "dead" code right now,
// see bug #75966.
//
bool nsLDAPServiceEntry::DeleteEntry()
{
mDelete = true;
return true;
}
// This is the end of the nsLDAPServiceEntry class
// Here begins the implementation for nsLDAPService
//
NS_IMPL_ISUPPORTS(nsLDAPService,
nsILDAPService,
nsILDAPMessageListener)
// constructor
//
nsLDAPService::nsLDAPService()
: mLock("nsLDAPService.mLock")
{
}
// destructor
//
nsLDAPService::~nsLDAPService()
{
}
// Initializer
//
nsresult nsLDAPService::Init()
{
return NS_OK;
}
// void addServer (in nsILDAPServer aServer);
NS_IMETHODIMP nsLDAPService::AddServer(nsILDAPServer *aServer)
{
nsLDAPServiceEntry *entry;
nsString key;
nsresult rv;
if (!aServer) {
NS_ERROR("nsLDAPService::AddServer: null pointer ");
return NS_ERROR_NULL_POINTER;
}
// Set up the hash key for the server entry
//
rv = aServer->GetKey(getter_Copies(key));
if (NS_FAILED(rv)) {
// Only pass along errors we are aware of
if ((rv == NS_ERROR_OUT_OF_MEMORY) || (rv == NS_ERROR_NULL_POINTER))
return rv;
else
return NS_ERROR_FAILURE;
}
// Create the new service server entry, and add it into the hash table
//
entry = new nsLDAPServiceEntry;
if (!entry) {
NS_ERROR("nsLDAPService::AddServer: out of memory ");
return NS_ERROR_OUT_OF_MEMORY;
}
if (!entry->Init()) {
delete entry;
NS_ERROR("nsLDAPService::AddServer: out of memory ");
return NS_ERROR_OUT_OF_MEMORY;
}
if (!entry->SetServer(aServer)) {
delete entry;
return NS_ERROR_FAILURE;
}
// We increment the refcount here for the server entry, when
// we purge a server completely from the service (TBD), we
// need to decrement the counter as well.
//
{
MutexAutoLock lock(mLock);
if (mServers.Get(key)) {
// Collision detected, lets just throw away this service entry
// and keep the old one.
//
delete entry;
return NS_ERROR_FAILURE;
}
mServers.Put(key, entry);
}
NS_ADDREF(aServer);
return NS_OK;
}
// void deleteServer (in wstring aKey);
NS_IMETHODIMP nsLDAPService::DeleteServer(const char16_t *aKey)
{
nsLDAPServiceEntry *entry;
MutexAutoLock lock(mLock);
// We should probably rename the key for this entry now that it's
// "deleted", so that we can add in a new one with the same ID.
// This is bug #77669.
//
mServers.Get(nsDependentString(aKey), &entry);
if (entry) {
if (entry->GetLeases() > 0) {
return NS_ERROR_FAILURE;
}
entry->DeleteEntry();
} else {
// There is no Server entry for this key
//
return NS_ERROR_FAILURE;
}
return NS_OK;
}
// nsILDAPServer getServer (in wstring aKey);
NS_IMETHODIMP nsLDAPService::GetServer(const char16_t *aKey,
nsILDAPServer **_retval)
{
nsLDAPServiceEntry *entry;
MutexAutoLock lock(mLock);
if (!_retval) {
NS_ERROR("nsLDAPService::GetServer: null pointer ");
return NS_ERROR_NULL_POINTER;
}
if (!mServers.Get(nsDependentString(aKey), &entry)) {
*_retval = 0;
return NS_ERROR_FAILURE;
}
if (!(*_retval = entry->GetServer().take())) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
//void requestConnection (in wstring aKey,
// in nsILDAPMessageListener aMessageListener);
NS_IMETHODIMP nsLDAPService::RequestConnection(const char16_t *aKey,
nsILDAPMessageListener *aListener)
{
nsLDAPServiceEntry *entry;
nsCOMPtr<nsILDAPConnection> conn;
nsCOMPtr<nsILDAPMessage> message;
nsresult rv;
if (!aListener) {
NS_ERROR("nsLDAPService::RequestConection: null pointer ");
return NS_ERROR_NULL_POINTER;
}
// Try to find a possibly cached connection and LDAP message.
//
{
MutexAutoLock lock(mLock);
if (!mServers.Get(nsDependentString(aKey), &entry)) {
return NS_ERROR_FAILURE;
}
entry->SetTimestamp();
conn = entry->GetConnection();
message = entry->GetMessage();
}
if (conn) {
if (message) {
// We already have the connection, and the message, ready to
// be used. This might be confusing, since we actually call
// the listener before this function returns, see bug #75899.
//
aListener->OnLDAPMessage(message);
return NS_OK;
}
} else {
rv = EstablishConnection(entry, aListener);
if (NS_FAILED(rv)) {
return rv;
}
}
// We got a new connection, now push the listeners on our stack,
// until we get the LDAP message back.
//
{
MutexAutoLock lock(mLock);
if (!mServers.Get(nsDependentString(aKey), &entry) ||
!entry->PushListener(static_cast<nsILDAPMessageListener *>
(aListener))) {
return NS_ERROR_FAILURE;
}
}
return NS_OK;
}
// nsILDAPConnection getConnection (in wstring aKey);
NS_IMETHODIMP nsLDAPService::GetConnection(const char16_t *aKey,
nsILDAPConnection **_retval)
{
nsLDAPServiceEntry *entry;
MutexAutoLock lock(mLock);
if (!_retval) {
NS_ERROR("nsLDAPService::GetConnection: null pointer ");
return NS_ERROR_NULL_POINTER;
}
if (!mServers.Get(nsDependentString(aKey), &entry)) {
*_retval = 0;
return NS_ERROR_FAILURE;
}
entry->SetTimestamp();
entry->IncrementLeases();
if (!(*_retval = entry->GetConnection().take())){
return NS_ERROR_FAILURE;
}
return NS_OK;
}
// void releaseConnection (in wstring aKey);
NS_IMETHODIMP nsLDAPService::ReleaseConnection(const char16_t *aKey)
{
nsLDAPServiceEntry *entry;
MutexAutoLock lock(mLock);
if (!mServers.Get(nsDependentString(aKey), &entry)) {
return NS_ERROR_FAILURE;
}
if (entry->GetLeases() > 0) {
entry->SetTimestamp();
entry->DecrementLeases();
} else {
// Releasing a non-leased connection is currently a No-Op.
//
}
return NS_OK;
}
// void reconnectConnection (in wstring aKey,
// in nsILDAPMessageListener aMessageListener);
NS_IMETHODIMP nsLDAPService::ReconnectConnection(const char16_t *aKey,
nsILDAPMessageListener *aListener)
{
nsLDAPServiceEntry *entry;
nsresult rv;
if (!aListener) {
NS_ERROR("nsLDAPService::ReconnectConnection: null pointer ");
return NS_ERROR_NULL_POINTER;
}
{
MutexAutoLock lock(mLock);
if (!mServers.Get(nsDependentString(aKey), &entry)) {
return NS_ERROR_FAILURE;
}
entry->SetTimestamp();
if (entry->IsRebinding()) {
if (!entry->PushListener(aListener)) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
// Clear the old connection and message, which should get garbaged
// collected now. We mark this as being "rebinding" now, and it
// we be marked as finished either if there's an error condition,
// or if the OnLDAPMessage() method gets called (i.e. bind() done).
//
entry->SetMessage(0);
entry->SetConnection(0);
// Get a new connection
//
entry->SetRebinding(true);
}
rv = EstablishConnection(entry, aListener);
if (NS_FAILED(rv)) {
return rv;
}
{
MutexAutoLock lock(mLock);
if (!entry->PushListener(static_cast<nsILDAPMessageListener *>
(aListener))) {
entry->SetRebinding(false);
return NS_ERROR_FAILURE;
}
}
return NS_OK;
}
/**
* Messages received are passed back via this function.
*
* @arg aMessage The message that was returned, 0 if none was.
*
* void OnLDAPMessage (in nsILDAPMessage aMessage)
*/
NS_IMETHODIMP
nsLDAPService::OnLDAPMessage(nsILDAPMessage *aMessage)
{
nsCOMPtr<nsILDAPOperation> operation;
nsCOMPtr<nsILDAPConnection> connection;
int32_t messageType;
// XXXleif: NULL messages are supposedly allowed, but the semantics
// are not definted (yet?). This is something to look out for...
//
// figure out what sort of message was returned
//
nsresult rv = aMessage->GetType(&messageType);
if (NS_FAILED(rv)) {
NS_ERROR("nsLDAPService::OnLDAPMessage(): unexpected error in "
"nsLDAPMessage::GetType()");
return NS_ERROR_UNEXPECTED;
}
switch (messageType) {
case LDAP_RES_BIND:
// a bind has completed
//
rv = aMessage->GetOperation(getter_AddRefs(operation));
if (NS_FAILED(rv)) {
NS_ERROR("nsLDAPService::OnLDAPMessage(): unexpected error in "
"nsLDAPMessage::GetOperation()");
return NS_ERROR_UNEXPECTED;
}
rv = operation->GetConnection(getter_AddRefs(connection));
if (NS_FAILED(rv)) {
NS_ERROR("nsLDAPService::OnLDAPMessage(): unexpected error in "
"nsLDAPOperation::GetConnection()");
return NS_ERROR_UNEXPECTED;
}
// Now we have the connection, lets find the corresponding
// server entry in the Service.
//
{
nsCOMPtr<nsILDAPMessageListener> listener;
nsCOMPtr<nsILDAPMessage> message;
nsLDAPServiceEntry *entry;
MutexAutoLock lock(mLock);
if (!mConnections.Get(connection, &entry)) {
return NS_ERROR_FAILURE;
}
message = entry->GetMessage();
if (message) {
// We already have a message, lets keep that one.
//
return NS_ERROR_FAILURE;
}
entry->SetRebinding(false);
entry->SetMessage(aMessage);
// Now process all the pending callbacks/listeners. We
// have to make sure to unlock before calling a listener,
// since it's likely to call back into us again.
//
while ((listener = entry->PopListener())) {
MutexAutoUnlock unlock(mLock);
listener->OnLDAPMessage(aMessage);
}
}
break;
default:
NS_WARNING("nsLDAPService::OnLDAPMessage(): unexpected LDAP message "
"received");
// get the console service so we can log a message
//
nsCOMPtr<nsIConsoleService> consoleSvc =
do_GetService("@mozilla.org/consoleservice;1", &rv);
if (NS_FAILED(rv)) {
NS_ERROR("nsLDAPChannel::OnLDAPMessage() couldn't get console "
"service");
break;
}
// log the message
//
rv = consoleSvc->LogStringMessage(
NS_LITERAL_STRING("LDAP: WARNING: nsLDAPService::OnLDAPMessage(): Unexpected LDAP message received").get());
NS_ASSERTION(NS_SUCCEEDED(rv), "nsLDAPService::OnLDAPMessage(): "
"consoleSvc->LogStringMessage() failed");
break;
}
return NS_OK;
}
// void onLDAPInit (in nsILDAPConnection aConn, in nsresult aStatus); */
//
NS_IMETHODIMP
nsLDAPService::OnLDAPInit(nsILDAPConnection *aConn, nsresult aStatus)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
// Helper function to establish an LDAP connection properly.
//
nsresult
nsLDAPService::EstablishConnection(nsLDAPServiceEntry *aEntry,
nsILDAPMessageListener *aListener)
{
nsCOMPtr<nsILDAPOperation> operation;
nsCOMPtr<nsILDAPServer> server;
nsCOMPtr<nsILDAPURL> url;
nsCOMPtr<nsILDAPConnection> conn, conn2;
nsCOMPtr<nsILDAPMessage> message;
nsAutoCString binddn;
nsAutoCString password;
uint32_t protocolVersion;
nsresult rv;
server = aEntry->GetServer();
if (!server) {
return NS_ERROR_FAILURE;
}
// Get username, password, and protocol version from the server entry.
//
rv = server->GetBinddn(binddn);
if (NS_FAILED(rv)) {
return NS_ERROR_FAILURE;
}
rv = server->GetPassword(password);
if (NS_FAILED(rv)) {
return NS_ERROR_FAILURE;
}
rv = server->GetProtocolVersion(&protocolVersion);
if (NS_FAILED(rv)) {
return NS_ERROR_FAILURE;
}
// Get the host and port out of the URL, which is in the server entry.
//
rv = server->GetUrl(getter_AddRefs(url));
if (NS_FAILED(rv)) {
return NS_ERROR_FAILURE;
}
// Create a new connection for this server.
//
conn = do_CreateInstance(kLDAPConnectionCID, &rv);
if (NS_FAILED(rv)) {
NS_ERROR("nsLDAPService::EstablishConnection(): could not create "
"@mozilla.org/network/ldap-connection;1");
return NS_ERROR_FAILURE;
}
rv = conn->Init(url, binddn, this, nullptr, protocolVersion);
if (NS_FAILED(rv)) {
switch (rv) {
// Only pass along errors we are aware of
//
case NS_ERROR_OUT_OF_MEMORY:
case NS_ERROR_NOT_AVAILABLE:
case NS_ERROR_FAILURE:
return rv;
case NS_ERROR_ILLEGAL_VALUE:
default:
return NS_ERROR_UNEXPECTED;
}
}
// Try to detect a collision, i.e. someone established a connection
// just before we did. If so, we drop ours. This code is somewhat
// similar to what happens in RequestConnection(), i.e. we try to
// call the listener directly if possible, and if not, push it on
// the stack of pending requests.
//
{
MutexAutoLock lock(mLock);
conn2 = aEntry->GetConnection();
message = aEntry->GetMessage();
}
if (conn2) {
// Drop the new connection, we can't use it.
//
conn = nullptr;
if (message) {
aListener->OnLDAPMessage(message);
return NS_OK;
}
{
MutexAutoLock lock(mLock);
if (!aEntry->PushListener(static_cast<nsILDAPMessageListener *>
(aListener))) {
return NS_ERROR_FAILURE;
}
}
return NS_OK;
}
// We made the connection, lets store it to the server entry,
// and also update the reverse lookup tables (for finding the
// server entry related to a particular connection).
//
{
MutexAutoLock lock(mLock);
aEntry->SetConnection(conn);
mConnections.Put(conn, aEntry);
}
// Setup the bind() operation.
//
operation = do_CreateInstance(kLDAPOperationCID, &rv);
if (NS_FAILED(rv)) {
return NS_ERROR_FAILURE;
}
rv = operation->Init(conn, this, nullptr);
if (NS_FAILED(rv)) {
return NS_ERROR_UNEXPECTED; // this should never happen
}
// Start a bind operation
//
// Here we need to support the password, see bug #75990
//
rv = operation->SimpleBind(password);
if (NS_FAILED(rv)) {
// Only pass along errors we are aware of
if ((rv == NS_ERROR_LDAP_ENCODING_ERROR) ||
(rv == NS_ERROR_FAILURE) ||
(rv == NS_ERROR_OUT_OF_MEMORY))
return rv;
else
return NS_ERROR_UNEXPECTED;
}
return NS_OK;
}
/* AString createFilter (in unsigned long aMaxSize, in AString aPattern, in AString aPrefix, in AString aSuffix, in AString aAttr, in AString aValue); */
NS_IMETHODIMP nsLDAPService::CreateFilter(uint32_t aMaxSize,
const nsACString & aPattern,
const nsACString & aPrefix,
const nsACString & aSuffix,
const nsACString & aAttr,
const nsACString & aValue,
nsACString & _retval)
{
if (!aMaxSize) {
return NS_ERROR_INVALID_ARG;
}
// figure out how big of an array we're going to need for the tokens,
// including a trailing NULL, and allocate space for it.
//
const char *iter = aValue.BeginReading();
const char *iterEnd = aValue.EndReading();
uint32_t numTokens = CountTokens(iter, iterEnd);
char **valueWords;
valueWords = static_cast<char **>(moz_xmalloc((numTokens + 1) *
sizeof(char *)));
if (!valueWords) {
return NS_ERROR_OUT_OF_MEMORY;
}
// build the array of values
//
uint32_t curToken = 0;
while (iter != iterEnd && curToken < numTokens ) {
valueWords[curToken] = NextToken(&iter, &iterEnd);
if ( !valueWords[curToken] ) {
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(curToken, valueWords);
return NS_ERROR_OUT_OF_MEMORY;
}
curToken++;
}
valueWords[numTokens] = 0; // end of array signal to LDAP C SDK
// make buffer to be used for construction
//
char *buffer = static_cast<char *>(moz_xmalloc(aMaxSize * sizeof(char)));
if (!buffer) {
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(numTokens, valueWords);
return NS_ERROR_OUT_OF_MEMORY;
}
// create the filter itself
//
nsresult rv;
int result = ldap_create_filter(buffer, aMaxSize,
const_cast<char *>(PromiseFlatCString(aPattern).get()),
const_cast<char *>(PromiseFlatCString(aPrefix).get()),
const_cast<char *>(PromiseFlatCString(aSuffix).get()),
const_cast<char *>(PromiseFlatCString(aAttr).get()),
const_cast<char *>(PromiseFlatCString(aValue).get()),
valueWords);
switch (result) {
case LDAP_SUCCESS:
rv = NS_OK;
break;
case LDAP_SIZELIMIT_EXCEEDED:
MOZ_LOG(gLDAPLogModule, mozilla::LogLevel::Debug,
("nsLDAPService::CreateFilter(): "
"filter longer than max size of %d generated",
aMaxSize));
rv = NS_ERROR_NOT_AVAILABLE;
break;
case LDAP_PARAM_ERROR:
rv = NS_ERROR_INVALID_ARG;
break;
default:
NS_ERROR("nsLDAPService::CreateFilter(): ldap_create_filter() "
"returned unexpected error");
rv = NS_ERROR_UNEXPECTED;
break;
}
_retval.Assign(buffer);
// done with the array and the buffer
//
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(numTokens, valueWords);
free(buffer);
return rv;
}
// Parse a distinguished name (DN) and returns the relative DN,
// base DN and the list of attributes that make up the relative DN.
NS_IMETHODIMP nsLDAPService::ParseDn(const char *aDn,
nsACString &aRdn,
nsACString &aBaseDn,
uint32_t *aRdnCount,
char ***aRdnAttrs)
{
NS_ENSURE_ARG_POINTER(aRdnCount);
NS_ENSURE_ARG_POINTER(aRdnAttrs);
// explode the DN
char **dnComponents = ldap_explode_dn(aDn, 0);
if (!dnComponents) {
NS_ERROR("nsLDAPService::ParseDn: parsing DN failed");
return NS_ERROR_UNEXPECTED;
}
// count DN components
if (!*dnComponents || !*(dnComponents + 1)) {
NS_ERROR("nsLDAPService::ParseDn: DN has too few components");
ldap_value_free(dnComponents);
return NS_ERROR_UNEXPECTED;
}
// get the base DN
nsAutoCString baseDn(nsDependentCString(*(dnComponents + 1)));
for (char **component = dnComponents + 2; *component; ++component) {
baseDn.AppendLiteral(",");
baseDn.Append(nsDependentCString(*component));
}
// explode the RDN
char **rdnComponents = ldap_explode_rdn(*dnComponents, 0);
if (!rdnComponents) {
NS_ERROR("nsLDAPService::ParseDn: parsing RDN failed");
ldap_value_free(dnComponents);
return NS_ERROR_UNEXPECTED;
}
// count RDN attributes
uint32_t rdnCount = 0;
for (char **component = rdnComponents; *component; ++component)
++rdnCount;
if (rdnCount < 1) {
NS_ERROR("nsLDAPService::ParseDn: RDN has too few components");
ldap_value_free(dnComponents);
ldap_value_free(rdnComponents);
return NS_ERROR_UNEXPECTED;
}
// get the RDN attribute names
char **attrNameArray = static_cast<char **>(
moz_xmalloc(rdnCount * sizeof(char *)));
if (!attrNameArray) {
NS_ERROR("nsLDAPService::ParseDn: out of memory ");
ldap_value_free(dnComponents);
ldap_value_free(rdnComponents);
return NS_ERROR_OUT_OF_MEMORY;
}
uint32_t index = 0;
for (char **component = rdnComponents; *component; ++component) {
uint32_t len = 0;
char *p;
for (p = *component; *p != '\0' && *p != '='; ++p)
++len;
if (*p != '=') {
NS_ERROR("nsLDAPService::parseDn: "
"could not find '=' in RDN component");
ldap_value_free(dnComponents);
ldap_value_free(rdnComponents);
return NS_ERROR_UNEXPECTED;
}
if (!(attrNameArray[index] = (char*)NS_Alloc(len + 1))) {
NS_ERROR("nsLDAPService::ParseDn: out of memory ");
ldap_value_free(dnComponents);
ldap_value_free(rdnComponents);
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(index, attrNameArray);
return NS_ERROR_OUT_OF_MEMORY;
}
memcpy(attrNameArray[index], *component, len);
*(attrNameArray[index] + len) = '\0';
++index;
}
// perform assignments
aRdn.Assign(*dnComponents);
aBaseDn.Assign(baseDn);
*aRdnCount = rdnCount;
*aRdnAttrs = attrNameArray;
ldap_value_free(dnComponents);
ldap_value_free(rdnComponents);
return NS_OK;
}
// Count the number of space-separated tokens between aIter and aIterEnd
//
uint32_t
nsLDAPService::CountTokens(const char *aIter,
const char *aIterEnd)
{
uint32_t count(0);
// keep iterating through the string until we hit the end
//
while (aIter != aIterEnd) {
// move past any leading spaces
//
while (aIter != aIterEnd &&
ldap_utf8isspace(const_cast<char *>(aIter))){
++aIter;
}
// move past all chars in this token
//
while (aIter != aIterEnd) {
if (ldap_utf8isspace(const_cast<char *>(aIter))) {
++count; // token finished; increment the count
++aIter; // move past the space
break;
}
++aIter; // move to next char
// if we've hit the end of this token and the end of this
// iterator simultaneous, be sure to bump the count, since we're
// never gonna hit the IsAsciiSpace where it's normally done.
//
if (aIter == aIterEnd) {
++count;
}
}
}
return count;
}
// return the next token in this iterator
//
char*
nsLDAPService::NextToken(const char **aIter,
const char **aIterEnd)
{
// move past any leading whitespace
//
while (*aIter != *aIterEnd &&
ldap_utf8isspace(const_cast<char *>(*aIter))) {
++(*aIter);
}
const char *start = *aIter;
// copy the token into our local variable
//
while (*aIter != *aIterEnd &&
!ldap_utf8isspace(const_cast<char *>(*aIter))) {
++(*aIter);
}
return ToNewCString(Substring(start, *aIter));
}

View file

@ -0,0 +1,116 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ldap.h"
#include "nsStringGlue.h"
#include "nsCOMArray.h"
#include "nsDataHashtable.h"
#include "nsILDAPService.h"
#include "nsILDAPMessage.h"
#include "nsILDAPMessageListener.h"
#include "nsCOMPtr.h"
#include "nsILDAPServer.h"
#include "nsILDAPConnection.h"
#include "nsILDAPMessage.h"
#include "mozilla/Mutex.h"
// 6a89ae33-7a90-430d-888c-0dede53a951a
//
#define NS_LDAPSERVICE_CID \
{ \
0x6a89ae33, 0x7a90, 0x430d, \
{0x88, 0x8c, 0x0d, 0xed, 0xe5, 0x3a, 0x95, 0x1a} \
}
// This is a little "helper" class, we use to store information
// related to one Service entry (one LDAP server).
//
class nsLDAPServiceEntry
{
public:
nsLDAPServiceEntry();
virtual ~nsLDAPServiceEntry() {};
bool Init();
inline uint32_t GetLeases();
inline void IncrementLeases();
inline bool DecrementLeases();
inline PRTime GetTimestamp();
inline void SetTimestamp();
inline already_AddRefed<nsILDAPServer> GetServer();
inline bool SetServer(nsILDAPServer *aServer);
inline already_AddRefed<nsILDAPConnection> GetConnection();
inline void SetConnection(nsILDAPConnection *aConnection);
inline already_AddRefed<nsILDAPMessage> GetMessage();
inline void SetMessage(nsILDAPMessage *aMessage);
inline already_AddRefed<nsILDAPMessageListener> PopListener();
inline bool PushListener(nsILDAPMessageListener *);
inline bool IsRebinding();
inline void SetRebinding(bool);
inline bool DeleteEntry();
protected:
uint32_t mLeases; // The number of leases currently granted
PRTime mTimestamp; // Last time this server was "used"
bool mDelete; // This entry is due for deletion
bool mRebinding; // Keep state if we are rebinding or not
nsCOMPtr<nsILDAPServer> mServer;
nsCOMPtr<nsILDAPConnection> mConnection;
nsCOMPtr<nsILDAPMessage> mMessage;
// Array holding all the pending callbacks (listeners) for this entry
nsCOMArray<nsILDAPMessageListener> mListeners;
};
// This is the interface we're implementing.
//
class nsLDAPService : public nsILDAPService, public nsILDAPMessageListener
{
public:
// interface decls
//
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSILDAPSERVICE
NS_DECL_NSILDAPMESSAGELISTENER
// constructor and destructor
//
nsLDAPService();
nsresult Init();
protected:
virtual ~nsLDAPService();
nsresult EstablishConnection(nsLDAPServiceEntry *,
nsILDAPMessageListener *);
// kinda like strtok_r, but with iterators. for use by
// createFilter
//
char *NextToken(const char **aIter, const char **aIterEnd);
// count how many tokens are in this string; for use by
// createFilter; note that unlike with NextToken, these params
// are copies, not references.
//
uint32_t CountTokens(const char * aIter, const char * aIterEnd);
mozilla::Mutex mLock; // Lock mechanism
// Hash table holding server entries
nsDataHashtable<nsStringHashKey, nsLDAPServiceEntry*> mServers;
// Hash table holding "reverse" lookups from connection to server
nsDataHashtable<nsVoidPtrHashKey, nsLDAPServiceEntry*> mConnections;
};

View file

@ -0,0 +1,386 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsLDAPSyncQuery.h"
#include "nsIServiceManager.h"
#include "nsILDAPErrors.h"
#include "nsThreadUtils.h"
#include "nsILDAPMessage.h"
#include "nsComponentManagerUtils.h"
#include "nsServiceManagerUtils.h"
#include "nsMemory.h"
// nsISupports Implementation
NS_IMPL_ISUPPORTS(nsLDAPSyncQuery, nsILDAPSyncQuery, nsILDAPMessageListener)
// Constructor
//
nsLDAPSyncQuery::nsLDAPSyncQuery() :
mFinished(false), // This is a control variable for event loop
mProtocolVersion(nsILDAPConnection::VERSION3)
{
}
// Destructor
//
nsLDAPSyncQuery::~nsLDAPSyncQuery()
{
}
// Messages received are passed back via this function.
// void OnLDAPMessage (in nsILDAPMessage aMessage)
//
NS_IMETHODIMP
nsLDAPSyncQuery::OnLDAPMessage(nsILDAPMessage *aMessage)
{
int32_t messageType;
// just in case.
//
if (!aMessage) {
return NS_OK;
}
// figure out what sort of message was returned
//
nsresult rv = aMessage->GetType(&messageType);
if (NS_FAILED(rv)) {
NS_ERROR("nsLDAPSyncQuery::OnLDAPMessage(): unexpected "
"error in aMessage->GetType()");
FinishLDAPQuery();
return NS_ERROR_UNEXPECTED;
}
switch (messageType) {
case nsILDAPMessage::RES_BIND:
// a bind has completed
//
return OnLDAPBind(aMessage);
case nsILDAPMessage::RES_SEARCH_ENTRY:
// a search entry has been returned
//
return OnLDAPSearchEntry(aMessage);
case nsILDAPMessage::RES_SEARCH_RESULT:
// the search is finished; we're all done
//
return OnLDAPSearchResult(aMessage);
default:
// Given the LDAP operations nsLDAPSyncQuery uses, we should
// never get here. If we do get here in a release build, it's
// probably a bug, but maybe it's the LDAP server doing something
// weird. Might as well try and continue anyway. The session should
// eventually get reaped by the timeout code, if necessary.
//
NS_ERROR("nsLDAPSyncQuery::OnLDAPMessage(): unexpected "
"LDAP message received");
return NS_OK;
}
}
// void onLDAPInit (in nsresult aStatus);
//
NS_IMETHODIMP
nsLDAPSyncQuery::OnLDAPInit(nsILDAPConnection *aConn, nsresult aStatus)
{
nsresult rv; // temp for xpcom return values
// create and initialize an LDAP operation (to be used for the bind)
//
mOperation = do_CreateInstance("@mozilla.org/network/ldap-operation;1",
&rv);
if (NS_FAILED(rv)) {
FinishLDAPQuery();
return NS_ERROR_FAILURE;
}
// our OnLDAPMessage accepts all result callbacks
//
rv = mOperation->Init(mConnection, this, nullptr);
if (NS_FAILED(rv)) {
FinishLDAPQuery();
return NS_ERROR_UNEXPECTED; // this should never happen
}
// kick off a bind operation
//
rv = mOperation->SimpleBind(EmptyCString());
if (NS_FAILED(rv)) {
FinishLDAPQuery();
return NS_ERROR_FAILURE;
}
return NS_OK;
}
nsresult
nsLDAPSyncQuery::OnLDAPBind(nsILDAPMessage *aMessage)
{
int32_t errCode;
mOperation = nullptr; // done with bind op; make nsCOMPtr release it
// get the status of the bind
//
nsresult rv = aMessage->GetErrorCode(&errCode);
if (NS_FAILED(rv)) {
NS_ERROR("nsLDAPSyncQuery::OnLDAPBind(): couldn't get "
"error code from aMessage");
FinishLDAPQuery();
return NS_ERROR_FAILURE;
}
// check to be sure the bind succeeded
//
if (errCode != nsILDAPErrors::SUCCESS) {
FinishLDAPQuery();
return NS_ERROR_FAILURE;
}
// ok, we're starting a search
//
return StartLDAPSearch();
}
nsresult
nsLDAPSyncQuery::OnLDAPSearchEntry(nsILDAPMessage *aMessage)
{
uint32_t attrCount;
char** attributes;
nsresult rv = aMessage->GetAttributes(&attrCount, &attributes);
if (NS_FAILED(rv))
{
NS_WARNING("nsLDAPSyncQuery:OnLDAPSearchEntry(): "
"aMessage->GetAttributes() failed");
FinishLDAPQuery();
return rv;
}
// Iterate through the attributes received in this message
for (uint32_t i = 0; i < attrCount; i++)
{
char16_t **vals;
uint32_t valueCount;
// Get the values of this attribute.
// XXX better failure handling
rv = aMessage->GetValues(attributes[i], &valueCount, &vals);
if (NS_FAILED(rv))
{
NS_WARNING("nsLDAPSyncQuery:OnLDAPSearchEntry(): "
"aMessage->GetValues() failed\n");
FinishLDAPQuery();
break;
}
// Store all values of this attribute in the mResults.
for (uint32_t j = 0; j < valueCount; j++) {
mResults.Append(char16_t('\n'));
mResults.AppendASCII(attributes[i]);
mResults.Append(char16_t('='));
mResults.Append(vals[j]);
}
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(valueCount, vals);
}
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(attrCount, attributes);
return rv;
}
nsresult
nsLDAPSyncQuery::OnLDAPSearchResult(nsILDAPMessage *aMessage)
{
// We are done with the LDAP search.
// Release the control variable for the eventloop and other members
//
FinishLDAPQuery();
return NS_OK;
}
nsresult
nsLDAPSyncQuery::StartLDAPSearch()
{
nsresult rv;
// create and initialize an LDAP operation (to be used for the search
//
mOperation =
do_CreateInstance("@mozilla.org/network/ldap-operation;1", &rv);
if (NS_FAILED(rv)) {
NS_ERROR("nsLDAPSyncQuery::StartLDAPSearch(): couldn't "
"create @mozilla.org/network/ldap-operation;1");
FinishLDAPQuery();
return NS_ERROR_FAILURE;
}
// initialize the LDAP operation object
//
rv = mOperation->Init(mConnection, this, nullptr);
if (NS_FAILED(rv)) {
NS_ERROR("nsLDAPSyncQuery::StartLDAPSearch(): couldn't "
"initialize LDAP operation");
FinishLDAPQuery();
return NS_ERROR_UNEXPECTED;
}
// get the search filter associated with the directory server url;
//
nsAutoCString urlFilter;
rv = mServerURL->GetFilter(urlFilter);
if (NS_FAILED(rv)) {
FinishLDAPQuery();
return NS_ERROR_UNEXPECTED;
}
// get the base dn to search
//
nsAutoCString dn;
rv = mServerURL->GetDn(dn);
if (NS_FAILED(rv)) {
FinishLDAPQuery();
return NS_ERROR_UNEXPECTED;
}
// and the scope
//
int32_t scope;
rv = mServerURL->GetScope(&scope);
if (NS_FAILED(rv)) {
FinishLDAPQuery();
return NS_ERROR_UNEXPECTED;
}
nsAutoCString attributes;
rv = mServerURL->GetAttributes(attributes);
if (NS_FAILED(rv)) {
FinishLDAPQuery();
return NS_ERROR_UNEXPECTED;
}
// time to kick off the search.
rv = mOperation->SearchExt(dn, scope, urlFilter, attributes, 0, 0);
if (NS_FAILED(rv)) {
FinishLDAPQuery();
return NS_ERROR_FAILURE;
}
return NS_OK;
}
// void initConnection ();
//
nsresult nsLDAPSyncQuery::InitConnection()
{
// Because mConnection->Init proxies back to the main thread, this
// better be the main thread.
NS_ENSURE_TRUE(NS_IsMainThread(), NS_ERROR_FAILURE);
nsresult rv; // temp for xpcom return values
// create an LDAP connection
//
mConnection = do_CreateInstance("@mozilla.org/network/ldap-connection;1",
&rv);
if (NS_FAILED(rv)) {
NS_ERROR("nsLDAPSyncQuery::InitConnection(): could "
"not create @mozilla.org/network/ldap-connection;1");
FinishLDAPQuery();
return NS_ERROR_FAILURE;
}
// have we been properly initialized?
//
if (!mServerURL) {
NS_ERROR("nsLDAPSyncQuery::InitConnection(): mServerURL "
"is NULL");
FinishLDAPQuery();
return NS_ERROR_NOT_INITIALIZED;
}
rv = mConnection->Init(mServerURL, EmptyCString(), this,
nullptr, mProtocolVersion);
if (NS_FAILED(rv)) {
FinishLDAPQuery();
return NS_ERROR_UNEXPECTED; // this should never happen
}
return NS_OK;
}
void
nsLDAPSyncQuery::FinishLDAPQuery()
{
// We are done with the LDAP operation.
// Release the Control variable for the eventloop
//
mFinished = true;
// Release member variables
//
mConnection = nullptr;
mOperation = nullptr;
mServerURL = nullptr;
}
/* wstring getQueryResults (in nsILDAPURL aServerURL, in unsigned long aVersion); */
NS_IMETHODIMP nsLDAPSyncQuery::GetQueryResults(nsILDAPURL *aServerURL,
uint32_t aProtocolVersion,
char16_t **_retval)
{
nsresult rv;
if (!aServerURL) {
NS_ERROR("nsLDAPSyncQuery::GetQueryResults() called without LDAP URL");
return NS_ERROR_FAILURE;
}
mServerURL = aServerURL;
mProtocolVersion = aProtocolVersion;
nsCOMPtr<nsIThread> currentThread = do_GetCurrentThread();
// Start an LDAP query.
// InitConnection will bind to the ldap server and post a OnLDAPMessage
// event. This event will trigger a search and the whole operation will
// be carried out by chain of events
//
rv = InitConnection();
if (NS_FAILED(rv))
return rv;
// We want this LDAP query to be synchronous while the XPCOM LDAP is
// async in nature. So this eventQueue handling will wait for the
// LDAP operation to be finished.
// mFinished controls the state of the LDAP opertion.
// It will be released in any case (success/failure)
// Run the event loop,
// mFinished is a control variable
//
while (!mFinished)
NS_ENSURE_STATE(NS_ProcessNextEvent(currentThread));
// Return results
//
if (!mResults.IsEmpty()) {
*_retval = ToNewUnicode(mResults);
if (!_retval)
rv = NS_ERROR_OUT_OF_MEMORY;
}
return rv;
}

View file

@ -0,0 +1,58 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsCOMPtr.h"
#include "nsILDAPConnection.h"
#include "nsILDAPOperation.h"
#include "nsILDAPMessageListener.h"
#include "nsILDAPURL.h"
#include "nsStringGlue.h"
#include "nsILDAPSyncQuery.h"
// DDDEE14E-ED81-4182-9323-C2AB22FBA68E
#define NS_LDAPSYNCQUERY_CID \
{ 0xdddee14e, 0xed81, 0x4182, \
{ 0x93, 0x23, 0xc2, 0xab, 0x22, 0xfb, 0xa6, 0x8e }}
class nsLDAPSyncQuery : public nsILDAPSyncQuery,
public nsILDAPMessageListener
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSILDAPMESSAGELISTENER
NS_DECL_NSILDAPSYNCQUERY
nsLDAPSyncQuery();
protected:
virtual ~nsLDAPSyncQuery();
nsCOMPtr<nsILDAPConnection> mConnection; // connection used for search
nsCOMPtr<nsILDAPOperation> mOperation; // current ldap op
nsCOMPtr<nsILDAPURL> mServerURL; // LDAP URL
bool mFinished; // control variable for eventQ
nsString mResults; // values to return
uint32_t mProtocolVersion; // LDAP version to use
nsresult InitConnection();
// check that we bound ok and start then call StartLDAPSearch
nsresult OnLDAPBind(nsILDAPMessage *aMessage);
// add to the results set
nsresult OnLDAPSearchEntry(nsILDAPMessage *aMessage);
nsresult OnLDAPSearchResult(nsILDAPMessage *aMessage);
// kick off a search
nsresult StartLDAPSearch();
// Clean up after the LDAP Query is done.
void FinishLDAPQuery();
};

View file

@ -0,0 +1,725 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsLDAPURL.h"
#include "netCore.h"
#include "plstr.h"
#include "nsCOMPtr.h"
#include "nsNetCID.h"
#include "nsComponentManagerUtils.h"
#include "nsIStandardURL.h"
#include "nsMsgUtils.h"
// The two schemes we support, LDAP and LDAPS
//
NS_NAMED_LITERAL_CSTRING(LDAP_SCHEME, "ldap");
NS_NAMED_LITERAL_CSTRING(LDAP_SSL_SCHEME, "ldaps");
NS_IMPL_ISUPPORTS(nsLDAPURL, nsILDAPURL, nsIURI)
nsLDAPURL::nsLDAPURL()
: mScope(SCOPE_BASE),
mOptions(0)
{
}
nsLDAPURL::~nsLDAPURL()
{
}
nsresult
nsLDAPURL::Init(uint32_t aUrlType, int32_t aDefaultPort,
const nsACString &aSpec, const char* aOriginCharset,
nsIURI *aBaseURI)
{
if (!mBaseURL)
{
mBaseURL = do_CreateInstance(NS_STANDARDURL_CONTRACTID);
if (!mBaseURL)
return NS_ERROR_OUT_OF_MEMORY;
}
nsresult rv;
nsCOMPtr<nsIStandardURL> standardURL(do_QueryInterface(mBaseURL, &rv));
NS_ENSURE_SUCCESS(rv, rv);
rv = standardURL->Init(aUrlType, aDefaultPort, aSpec, aOriginCharset,
aBaseURI);
NS_ENSURE_SUCCESS(rv, rv);
// Now get the spec from the mBaseURL in case it was a relative one
nsCString spec;
rv = mBaseURL->GetSpec(spec);
NS_ENSURE_SUCCESS(rv, rv);
return SetSpec(spec);
}
void
nsLDAPURL::GetPathInternal(nsCString &aPath)
{
aPath.Assign('/');
if (!mDN.IsEmpty())
aPath.Append(mDN);
if (!mAttributes.IsEmpty())
aPath.Append('?');
// If mAttributes isn't empty, cut off the internally stored commas at start
// and end, and append to the path.
if (!mAttributes.IsEmpty())
aPath.Append(Substring(mAttributes, 1, mAttributes.Length() - 2));
if (mScope || !mFilter.IsEmpty())
{
aPath.Append((mAttributes.IsEmpty() ? "??" : "?"));
if (mScope)
{
if (mScope == SCOPE_ONELEVEL)
aPath.Append("one");
else if (mScope == SCOPE_SUBTREE)
aPath.Append("sub");
}
if (!mFilter.IsEmpty())
{
aPath.Append('?');
aPath.Append(mFilter);
}
}
}
nsresult
nsLDAPURL::SetPathInternal(const nsCString &aPath)
{
LDAPURLDesc *desc;
// This is from the LDAP C-SDK, which currently doesn't
// support everything from RFC 2255... :(
//
int err = ldap_url_parse(aPath.get(), &desc);
switch (err) {
case LDAP_SUCCESS: {
// The base URL can pick up the host & port details and deal with them
// better than we can
mDN = desc->lud_dn;
mScope = desc->lud_scope;
mFilter = desc->lud_filter;
mOptions = desc->lud_options;
nsresult rv = SetAttributeArray(desc->lud_attrs);
if (NS_FAILED(rv))
return rv;
ldap_free_urldesc(desc);
return NS_OK;
}
case LDAP_URL_ERR_NOTLDAP:
case LDAP_URL_ERR_NODN:
case LDAP_URL_ERR_BADSCOPE:
return NS_ERROR_MALFORMED_URI;
case LDAP_URL_ERR_MEM:
NS_ERROR("nsLDAPURL::SetSpec: out of memory ");
return NS_ERROR_OUT_OF_MEMORY;
case LDAP_URL_ERR_PARAM:
return NS_ERROR_INVALID_POINTER;
}
// This shouldn't happen...
return NS_ERROR_UNEXPECTED;
}
// A string representation of the URI. Setting the spec
// causes the new spec to be parsed, initializing the URI. Setting
// the spec (or any of the accessors) causes also any currently
// open streams on the URI's channel to be closed.
NS_IMETHODIMP
nsLDAPURL::GetSpec(nsACString &_retval)
{
if (!mBaseURL)
return NS_ERROR_NOT_INITIALIZED;
return mBaseURL->GetSpec(_retval);
}
NS_IMETHODIMP
nsLDAPURL::SetSpec(const nsACString &aSpec)
{
if (!mBaseURL)
return NS_ERROR_NOT_INITIALIZED;
// Cache the original spec in case we don't like what we've been passed and
// need to reset ourselves.
nsCString originalSpec;
nsresult rv = mBaseURL->GetSpec(originalSpec);
NS_ENSURE_SUCCESS(rv, rv);
rv = mBaseURL->SetSpec(aSpec);
NS_ENSURE_SUCCESS(rv, rv);
rv = SetPathInternal(PromiseFlatCString(aSpec));
if (NS_FAILED(rv))
mBaseURL->SetSpec(originalSpec);
return rv;
}
NS_IMETHODIMP nsLDAPURL::GetPrePath(nsACString &_retval)
{
if (!mBaseURL)
return NS_ERROR_NOT_INITIALIZED;
return mBaseURL->GetPrePath(_retval);
}
NS_IMETHODIMP nsLDAPURL::GetScheme(nsACString &_retval)
{
if (!mBaseURL)
return NS_ERROR_NOT_INITIALIZED;
return mBaseURL->GetScheme(_retval);
}
NS_IMETHODIMP nsLDAPURL::SetScheme(const nsACString &aScheme)
{
if (!mBaseURL)
return NS_ERROR_NOT_INITIALIZED;
if (aScheme.Equals(LDAP_SCHEME, nsCaseInsensitiveCStringComparator()))
mOptions &= !OPT_SECURE;
else if (aScheme.Equals(LDAP_SSL_SCHEME,
nsCaseInsensitiveCStringComparator()))
mOptions |= OPT_SECURE;
else
return NS_ERROR_MALFORMED_URI;
return mBaseURL->SetScheme(aScheme);
}
NS_IMETHODIMP
nsLDAPURL::GetUserPass(nsACString &_retval)
{
_retval.Truncate();
return NS_OK;
}
NS_IMETHODIMP
nsLDAPURL::SetUserPass(const nsACString &aUserPass)
{
return NS_OK;
}
NS_IMETHODIMP
nsLDAPURL::GetUsername(nsACString &_retval)
{
_retval.Truncate();
return NS_OK;
}
NS_IMETHODIMP
nsLDAPURL::SetUsername(const nsACString &aUsername)
{
return NS_OK;
}
NS_IMETHODIMP
nsLDAPURL::GetPassword(nsACString &_retval)
{
_retval.Truncate();
return NS_OK;
}
NS_IMETHODIMP
nsLDAPURL::SetPassword(const nsACString &aPassword)
{
return NS_OK;
}
NS_IMETHODIMP
nsLDAPURL::GetHostPort(nsACString &_retval)
{
if (!mBaseURL)
return NS_ERROR_NOT_INITIALIZED;
return mBaseURL->GetHostPort(_retval);
}
NS_IMETHODIMP
nsLDAPURL::SetHostPort(const nsACString &aHostPort)
{
if (!mBaseURL)
return NS_ERROR_NOT_INITIALIZED;
return mBaseURL->SetHostPort(aHostPort);
}
NS_IMETHODIMP
nsLDAPURL::SetHostAndPort(const nsACString &aHostPort)
{
if (!mBaseURL)
return NS_ERROR_NOT_INITIALIZED;
return mBaseURL->SetHostAndPort(aHostPort);
}
NS_IMETHODIMP
nsLDAPURL::GetHost(nsACString &_retval)
{
if (!mBaseURL)
return NS_ERROR_NOT_INITIALIZED;
return mBaseURL->GetHost(_retval);
}
NS_IMETHODIMP
nsLDAPURL::SetHost(const nsACString &aHost)
{
if (!mBaseURL)
return NS_ERROR_NOT_INITIALIZED;
return mBaseURL->SetHost(aHost);
}
NS_IMETHODIMP
nsLDAPURL::GetPort(int32_t *_retval)
{
if (!mBaseURL)
return NS_ERROR_NOT_INITIALIZED;
return mBaseURL->GetPort(_retval);
}
NS_IMETHODIMP
nsLDAPURL::SetPort(int32_t aPort)
{
if (!mBaseURL)
return NS_ERROR_NOT_INITIALIZED;
return mBaseURL->SetPort(aPort);
}
NS_IMETHODIMP nsLDAPURL::GetPath(nsACString &_retval)
{
if (!mBaseURL)
return NS_ERROR_NOT_INITIALIZED;
return mBaseURL->GetPath(_retval);
}
NS_IMETHODIMP nsLDAPURL::SetPath(const nsACString &aPath)
{
if (!mBaseURL)
return NS_ERROR_NOT_INITIALIZED;
nsresult rv = SetPathInternal(PromiseFlatCString(aPath));
NS_ENSURE_SUCCESS(rv, rv);
return mBaseURL->SetPath(aPath);
}
NS_IMETHODIMP nsLDAPURL::GetAsciiSpec(nsACString &_retval)
{
if (!mBaseURL)
return NS_ERROR_NOT_INITIALIZED;
// XXX handle extra items?
return mBaseURL->GetAsciiSpec(_retval);
}
NS_IMETHODIMP nsLDAPURL::GetAsciiHost(nsACString &_retval)
{
if (!mBaseURL)
return NS_ERROR_NOT_INITIALIZED;
return mBaseURL->GetAsciiHost(_retval);
}
NS_IMETHODIMP
nsLDAPURL::GetAsciiHostPort(nsACString &_retval)
{
if (!mBaseURL)
return NS_ERROR_NOT_INITIALIZED;
return mBaseURL->GetAsciiHostPort(_retval);
}
NS_IMETHODIMP nsLDAPURL::GetOriginCharset(nsACString &result)
{
if (!mBaseURL)
return NS_ERROR_NOT_INITIALIZED;
return mBaseURL->GetOriginCharset(result);
}
// boolean equals (in nsIURI other)
// (based on nsSimpleURI::Equals)
NS_IMETHODIMP nsLDAPURL::Equals(nsIURI *other, bool *_retval)
{
*_retval = false;
if (other)
{
nsresult rv;
nsCOMPtr<nsILDAPURL> otherURL(do_QueryInterface(other, &rv));
if (NS_SUCCEEDED(rv))
{
nsAutoCString thisSpec, otherSpec;
uint32_t otherOptions;
rv = GetSpec(thisSpec);
NS_ENSURE_SUCCESS(rv, rv);
rv = otherURL->GetSpec(otherSpec);
NS_ENSURE_SUCCESS(rv, rv);
rv = otherURL->GetOptions(&otherOptions);
NS_ENSURE_SUCCESS(rv, rv);
if (thisSpec == otherSpec && mOptions == otherOptions)
*_retval = true;
}
}
return NS_OK;
}
// boolean schemeIs(in const char * scheme);
//
NS_IMETHODIMP nsLDAPURL::SchemeIs(const char *aScheme, bool *aEquals)
{
if (!mBaseURL)
return NS_ERROR_NOT_INITIALIZED;
return mBaseURL->SchemeIs(aScheme, aEquals);
}
// nsIURI clone ();
//
nsresult
nsLDAPURL::CloneInternal(RefHandlingEnum aRefHandlingMode,
const nsACString& newRef, nsIURI** aResult)
{
NS_ENSURE_ARG_POINTER(aResult);
nsLDAPURL *clone = new nsLDAPURL();
if (!clone)
return NS_ERROR_OUT_OF_MEMORY;
clone->mDN = mDN;
clone->mScope = mScope;
clone->mFilter = mFilter;
clone->mOptions = mOptions;
clone->mAttributes = mAttributes;
nsresult rv;
if (aRefHandlingMode == eHonorRef) {
rv = mBaseURL->Clone(getter_AddRefs(clone->mBaseURL));
} else if (aRefHandlingMode == eReplaceRef) {
rv = mBaseURL->CloneWithNewRef(newRef, getter_AddRefs(clone->mBaseURL));
} else {
rv = mBaseURL->CloneIgnoringRef(getter_AddRefs(clone->mBaseURL));
}
NS_ENSURE_SUCCESS(rv, rv);
NS_ADDREF(*aResult = clone);
return NS_OK;
}
NS_IMETHODIMP
nsLDAPURL::Clone(nsIURI** result)
{
return CloneInternal(eHonorRef, EmptyCString(), result);
}
NS_IMETHODIMP
nsLDAPURL::CloneIgnoringRef(nsIURI** result)
{
return CloneInternal(eIgnoreRef, EmptyCString(), result);
}
NS_IMETHODIMP
nsLDAPURL::CloneWithNewRef(const nsACString& newRef, nsIURI** result)
{
return CloneInternal(eReplaceRef, newRef, result);
}
// string resolve (in string relativePath);
//
NS_IMETHODIMP nsLDAPURL::Resolve(const nsACString &relativePath,
nsACString &_retval)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
// The following attributes come from nsILDAPURL
// attribute AUTF8String dn;
//
NS_IMETHODIMP nsLDAPURL::GetDn(nsACString& _retval)
{
_retval.Assign(mDN);
return NS_OK;
}
NS_IMETHODIMP nsLDAPURL::SetDn(const nsACString& aDn)
{
if (!mBaseURL)
return NS_ERROR_NOT_INITIALIZED;
mDN.Assign(aDn);
// Now get the current path
nsCString newPath;
GetPathInternal(newPath);
// and update the base url
return mBaseURL->SetPath(newPath);
}
NS_IMETHODIMP nsLDAPURL::GetAttributes(nsACString &aAttributes)
{
if (mAttributes.IsEmpty())
{
aAttributes.Truncate();
return NS_OK;
}
NS_ASSERTION(mAttributes[0] == ',' &&
mAttributes[mAttributes.Length() - 1] == ',',
"mAttributes does not begin and end with a comma");
// We store the string internally with comma before and after, so strip
// them off here.
aAttributes = Substring(mAttributes, 1, mAttributes.Length() - 2);
return NS_OK;
}
NS_IMETHODIMP nsLDAPURL::SetAttributes(const nsACString &aAttributes)
{
if (!mBaseURL)
return NS_ERROR_NOT_INITIALIZED;
if (aAttributes.IsEmpty())
mAttributes.Truncate();
else
{
// We need to make sure we start off the string with a comma.
if (aAttributes[0] != ',')
mAttributes = ',';
mAttributes.Append(aAttributes);
// Also end with a comma if appropriate.
if (mAttributes[mAttributes.Length() - 1] != ',')
mAttributes.Append(',');
}
// Now get the current path
nsCString newPath;
GetPathInternal(newPath);
// and update the base url
return mBaseURL->SetPath(newPath);
}
nsresult nsLDAPURL::SetAttributeArray(char** aAttributes)
{
mAttributes.Truncate();
while (aAttributes && *aAttributes)
{
// Always start with a comma as that's what we store internally.
mAttributes.Append(',');
mAttributes.Append(*aAttributes);
++aAttributes;
}
// Add a comma on the end if we have something.
if (!mAttributes.IsEmpty())
mAttributes.Append(',');
return NS_OK;
}
NS_IMETHODIMP nsLDAPURL::AddAttribute(const nsACString &aAttribute)
{
if (!mBaseURL)
return NS_ERROR_NOT_INITIALIZED;
if (mAttributes.IsEmpty())
{
mAttributes = ',';
mAttributes.Append(aAttribute);
mAttributes.Append(',');
}
else
{
// Wrap the attribute in commas, so that we can do an exact match.
nsAutoCString findAttribute(",");
findAttribute.Append(aAttribute);
findAttribute.Append(',');
// Check to see if the attribute is already stored. If it is, then also
// check to see if it is the last attribute in the string, or if the next
// character is a comma, this means we won't match substrings.
int32_t pos = mAttributes.Find(findAttribute, CaseInsensitiveCompare);
if (pos != -1)
return NS_OK;
mAttributes.Append(Substring(findAttribute, 1));
}
// Now get the current path
nsCString newPath;
GetPathInternal(newPath);
// and update the base url
return mBaseURL->SetPath(newPath);
}
NS_IMETHODIMP nsLDAPURL::RemoveAttribute(const nsACString &aAttribute)
{
if (!mBaseURL)
return NS_ERROR_NOT_INITIALIZED;
if (mAttributes.IsEmpty())
return NS_OK;
nsAutoCString findAttribute(",");
findAttribute.Append(aAttribute);
findAttribute.Append(',');
if (mAttributes.Equals(findAttribute, nsCaseInsensitiveCStringComparator()))
mAttributes.Truncate();
else
{
int32_t pos = mAttributes.Find(findAttribute, CaseInsensitiveCompare);
if (pos == -1)
return NS_OK;
mAttributes.Cut(pos, findAttribute.Length() - 1);
}
// Now get the current path
nsCString newPath;
GetPathInternal(newPath);
// and update the base url
return mBaseURL->SetPath(newPath);
}
NS_IMETHODIMP nsLDAPURL::HasAttribute(const nsACString &aAttribute,
bool *_retval)
{
NS_ENSURE_ARG_POINTER(_retval);
nsAutoCString findAttribute(",");
findAttribute.Append(aAttribute);
findAttribute.Append(',');
*_retval = mAttributes.Find(findAttribute, CaseInsensitiveCompare) != -1;
return NS_OK;
}
NS_IMETHODIMP nsLDAPURL::GetScope(int32_t *_retval)
{
NS_ENSURE_ARG_POINTER(_retval);
*_retval = mScope;
return NS_OK;
}
NS_IMETHODIMP nsLDAPURL::SetScope(int32_t aScope)
{
if (!mBaseURL)
return NS_ERROR_NOT_INITIALIZED;
// Only allow scopes supported by the C-SDK
if ((aScope != SCOPE_BASE) && (aScope != SCOPE_ONELEVEL) &&
(aScope != SCOPE_SUBTREE))
return NS_ERROR_MALFORMED_URI;
mScope = aScope;
// Now get the current path
nsCString newPath;
GetPathInternal(newPath);
// and update the base url
return mBaseURL->SetPath(newPath);
}
NS_IMETHODIMP nsLDAPURL::GetFilter(nsACString& _retval)
{
_retval.Assign(mFilter);
return NS_OK;
}
NS_IMETHODIMP nsLDAPURL::SetFilter(const nsACString& aFilter)
{
if (!mBaseURL)
return NS_ERROR_NOT_INITIALIZED;
mFilter.Assign(aFilter);
if (mFilter.IsEmpty())
mFilter.AssignLiteral("(objectclass=*)");
// Now get the current path
nsCString newPath;
GetPathInternal(newPath);
// and update the base url
return mBaseURL->SetPath(newPath);
}
NS_IMETHODIMP nsLDAPURL::GetOptions(uint32_t *_retval)
{
NS_ENSURE_ARG_POINTER(_retval);
*_retval = mOptions;
return NS_OK;
}
NS_IMETHODIMP nsLDAPURL::SetOptions(uint32_t aOptions)
{
// Secure is the only option supported at the moment
if ((mOptions & OPT_SECURE) == (aOptions & OPT_SECURE))
return NS_OK;
mOptions = aOptions;
if ((aOptions & OPT_SECURE) == OPT_SECURE)
return SetScheme(LDAP_SSL_SCHEME);
return SetScheme(LDAP_SCHEME);
}
NS_IMETHODIMP nsLDAPURL::SetRef(const nsACString &aRef)
{
return mBaseURL->SetRef(aRef);
}
NS_IMETHODIMP
nsLDAPURL::GetRef(nsACString &result)
{
return mBaseURL->GetRef(result);
}
NS_IMETHODIMP nsLDAPURL::EqualsExceptRef(nsIURI *other, bool *result)
{
return mBaseURL->EqualsExceptRef(other, result);
}
NS_IMETHODIMP
nsLDAPURL::GetSpecIgnoringRef(nsACString &result)
{
return mBaseURL->GetSpecIgnoringRef(result);
}
NS_IMETHODIMP
nsLDAPURL::GetHasRef(bool *result)
{
return mBaseURL->GetHasRef(result);
}

View file

@ -0,0 +1,61 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ldap.h"
#include "nsStringGlue.h"
#include "nsILDAPURL.h"
#include "nsCOMPtr.h"
// cb7c67f8-0053-4072-89e9-501cbd1b35ab
#define NS_LDAPURL_CID \
{ 0xcb7c67f8, 0x0053, 0x4072, \
{ 0x89, 0xe9, 0x50, 0x1c, 0xbd, 0x1b, 0x35, 0xab}}
/**
* nsLDAPURL
*
* nsLDAPURL uses an nsStandardURL stored in mBaseURL as its main url formatter.
*
* This is done to ensure that the pre-path sections of the URI are correctly
* formatted and to re-use the functions for nsIURI as appropriate.
*
* Handling of the path sections of the URI are done within nsLDAPURL/parts of
* the LDAP c-sdk. nsLDAPURL holds the individual sections of the path of the
* URI locally (to allow convenient get/set), but always updates the mBaseURL
* when one changes to ensure that mBaseURL.spec and the local data are kept
* consistent.
*/
class nsLDAPURL : public nsILDAPURL
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIURI
NS_DECL_NSILDAPURL
nsLDAPURL();
protected:
enum RefHandlingEnum {
eIgnoreRef,
eHonorRef,
eReplaceRef
};
virtual ~nsLDAPURL();
void GetPathInternal(nsCString &aPath);
nsresult SetPathInternal(const nsCString &aPath);
nsresult SetAttributeArray(char** aAttributes);
nsresult CloneInternal(RefHandlingEnum aRefHandlingMode,
const nsACString& newRef, nsIURI** aResult);
nsCString mDN; // Base Distinguished Name (Base DN)
int32_t mScope; // Search scope (base, one or sub)
nsCString mFilter; // LDAP search filter
uint32_t mOptions; // Options
nsCString mAttributes;
nsCOMPtr<nsIURI> mBaseURL;
};

View file

@ -0,0 +1,147 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* This module contains helper functions and macros for converting directory
module to frozen linkage.
*/
#include "nsServiceManagerUtils.h"
#include "nsStringGlue.h"
#include <ctype.h>
#ifdef MOZILLA_INTERNAL_API
/* Internal API helper macros */
#define LdapCompressWhitespace(str) \
(str).CompressWhitespace()
#else // MOZILLA_INTERNAL_API
/* Frozen linkage helper functions */
/* This macro has been copied from msgcore.h */
#define IS_SPACE(VAL) \
(((((PRIntn)(VAL)) & 0x7f) == ((PRIntn)(VAL))) && isspace((PRIntn)(VAL)))
/* This function has been copied from nsMsgUtils.cpp */
inline void LdapCompressWhitespace(nsCString& aString)
{
// This code is frozen linkage specific
aString.Trim(" \f\n\r\t\v");
char *start, *end;
aString.BeginWriting(&start, &end);
for (char *cur = start; cur < end; ++cur) {
if (!IS_SPACE(*cur))
continue;
*cur = ' ';
if (!IS_SPACE(*(cur + 1)))
continue;
// Loop through the white space
char *wend = cur + 2;
while (IS_SPACE(*wend))
++wend;
uint32_t wlen = wend - cur - 1;
// fix "end"
end -= wlen;
// move everything forwards a bit
for (char *m = cur + 1; m < end; ++m) {
*m = *(m + wlen);
}
}
// Set the new length.
aString.SetLength(end - start);
}
/*
* Function copied from nsReadableUtils.
* Migrating to frozen linkage is the only change done
*/
inline
bool IsUTF8(const nsACString& aString)
{
const char *done_reading = aString.EndReading();
int32_t state = 0;
bool overlong = false;
bool surrogate = false;
bool nonchar = false;
uint16_t olupper = 0; // overlong byte upper bound.
uint16_t slower = 0; // surrogate byte lower bound.
const char *ptr = aString.BeginReading();
while (ptr < done_reading) {
uint8_t c;
if (0 == state) {
c = *ptr++;
if ((c & 0x80) == 0x00)
continue;
if ( c <= 0xC1 ) // [80-BF] where not expected, [C0-C1] for overlong.
return false;
else if ((c & 0xE0) == 0xC0)
state = 1;
else if ((c & 0xF0) == 0xE0) {
state = 2;
if ( c == 0xE0 ) { // to exclude E0[80-9F][80-BF]
overlong = true;
olupper = 0x9F;
} else if ( c == 0xED ) { // ED[A0-BF][80-BF] : surrogate codepoint
surrogate = true;
slower = 0xA0;
} else if ( c == 0xEF ) // EF BF [BE-BF] : non-character
nonchar = true;
} else if ( c <= 0xF4 ) { // XXX replace /w UTF8traits::is4byte when it's updated to exclude [F5-F7].(bug 199090)
state = 3;
nonchar = true;
if ( c == 0xF0 ) { // to exclude F0[80-8F][80-BF]{2}
overlong = true;
olupper = 0x8F;
}
else if ( c == 0xF4 ) { // to exclude F4[90-BF][80-BF]
// actually not surrogates but codepoints beyond 0x10FFFF
surrogate = true;
slower = 0x90;
}
} else
return false; // Not UTF-8 string
}
while (ptr < done_reading && state) {
c = *ptr++;
--state;
// non-character : EF BF [BE-BF] or F[0-7] [89AB]F BF [BE-BF]
if ( nonchar && ( !state && c < 0xBE ||
state == 1 && c != 0xBF ||
state == 2 && 0x0F != (0x0F & c) ))
nonchar = false;
if ((c & 0xC0) != 0x80 || overlong && c <= olupper ||
surrogate && slower <= c || nonchar && !state )
return false; // Not UTF-8 string
overlong = surrogate = false;
}
}
return !state; // state != 0 at the end indicates an invalid UTF-8 seq.
}
#define kNotFound -1
#define nsCaseInsensitiveCStringComparator() \
CaseInsensitiveCompare
#define nsCaseInsensitiveStringComparator() \
CaseInsensitiveCompare
#endif // MOZILLA_INTERNAL_API