From be2a8e8cc8afcfa6bc5ac08efb4689c43bb94aaf Mon Sep 17 00:00:00 2001
From: Quanah Gibson-Mount <quanah@openldap.org>
Date: Mon, 10 Nov 2008 22:55:48 +0000
Subject: [PATCH] ITS#5784

---
 CHANGES                                       |   1 +
 clients/tools/common.c                        |  43 ++
 .../draft-masarati-ldap-whatfailed-xx.txt     | 672 ++++++++++++++++++
 doc/drafts/draft-masarati-ldap-whatfailed.xml | 240 +++++++
 include/ldap.h                                |   2 +
 servers/slapd/backend.c                       |   6 +
 servers/slapd/controls.c                      | 203 +++++-
 servers/slapd/proto-slap.h                    |   7 +
 servers/slapd/slap.h                          |   9 +
 9 files changed, 1166 insertions(+), 17 deletions(-)
 create mode 100644 doc/drafts/draft-masarati-ldap-whatfailed-xx.txt
 create mode 100644 doc/drafts/draft-masarati-ldap-whatfailed.xml

diff --git a/CHANGES b/CHANGES
index daa2c0449c..c91d6c1219 100644
--- a/CHANGES
+++ b/CHANGES
@@ -18,6 +18,7 @@ OpenLDAP 2.4.13 Engineering
 	Fixed slapd statslog printing of released entry (ITS#5775)
 	Added slapd support for certificateListExactMatch (ITS#5700)
 	Fixed slapd syncrepl MOD of attrs with no EQ rule (ITS#5781)
+	Added slapd What failed? control (ITS#5784)
 	Fixed slapd-bdb/hdb invalid db crash (ITS#5698)
 	Added slapd-bdb/hdb dbpagesize keyword
 	Added slapd-bdb/hdb checksum keyword
diff --git a/clients/tools/common.c b/clients/tools/common.c
index 58d5e6bf49..cda39c9f8c 100644
--- a/clients/tools/common.c
+++ b/clients/tools/common.c
@@ -138,6 +138,9 @@ static int print_sss( LDAP *ld, LDAPControl *ctrl );
 #ifdef LDAP_CONTROL_X_DEREF
 static int print_deref( LDAP *ld, LDAPControl *ctrl );
 #endif
+#ifdef LDAP_CONTROL_X_WHATFAILED
+static int print_whatfailed( LDAP *ld, LDAPControl *ctrl );
+#endif
 
 static struct tool_ctrls_t {
 	const char	*oid;
@@ -153,6 +156,9 @@ static struct tool_ctrls_t {
 	{ LDAP_CONTROL_SORTRESPONSE,	TOOL_SEARCH,	print_sss },
 #ifdef LDAP_CONTROL_X_DEREF
 	{ LDAP_CONTROL_X_DEREF,				TOOL_SEARCH,	print_deref },
+#endif
+#ifdef LDAP_CONTROL_X_WHATFAILED
+	{ LDAP_CONTROL_X_WHATFAILED,			TOOL_ALL,	print_whatfailed },
 #endif
 	{ NULL,						0,		NULL }
 };
@@ -1966,6 +1972,43 @@ done:;
 }
 #endif
 
+#ifdef LDAP_CONTROL_X_WHATFAILED
+static int
+print_whatfailed( LDAP *ld, LDAPControl *ctrl )
+{
+	BerElement *ber;
+	ber_tag_t tag;
+	ber_len_t siz;
+	BerVarray bva = NULL;
+
+	/* Create a BerElement from the berval returned in the control. */
+	ber = ber_init( &ctrl->ldctl_value );
+
+	if ( ber == NULL ) {
+		return LDAP_NO_MEMORY;
+	}
+
+	siz = sizeof(struct berval);
+	tag = ber_scanf( ber, "[M]", &bva, &siz, 0 );
+	if ( tag != LBER_ERROR ) {
+		int i;
+
+		tool_write_ldif( LDIF_PUT_COMMENT, " what failed:", NULL, 0 );
+
+		for ( i = 0; bva[i].bv_val != NULL; i++ ) {
+			tool_write_ldif( LDIF_PUT_COMMENT, NULL, bva[i].bv_val, bva[i].bv_len );
+		}
+
+		ldap_memfree( bva );
+	}
+
+        ber_free( ber, 1 );
+
+
+	return 0;
+}
+#endif
+
 #ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST
 static int
 print_ppolicy( LDAP *ld, LDAPControl *ctrl )
diff --git a/doc/drafts/draft-masarati-ldap-whatfailed-xx.txt b/doc/drafts/draft-masarati-ldap-whatfailed-xx.txt
new file mode 100644
index 0000000000..a98c341077
--- /dev/null
+++ b/doc/drafts/draft-masarati-ldap-whatfailed-xx.txt
@@ -0,0 +1,672 @@
+
+
+
+Network Working Group                                        P. Masarati
+Internet-Draft                                     Politecnico di Milano
+Intended status: Standards Track                            October 2008
+Expires: April 4, 2009
+
+
+                      LDAP "What Failed?" Control
+                   draft-masarati-ldap-whatfailed.txt
+
+Status of this Memo
+
+   By submitting this Internet-Draft, each author represents that any
+   applicable patent or other IPR claims of which he or she is aware
+   have been or will be disclosed, and any of which he or she becomes
+   aware will be disclosed, in accordance with Section 6 of BCP 79.
+
+   Internet-Drafts are working documents of the Internet Engineering
+   Task Force (IETF), its areas, and its working groups.  Note that
+   other groups may also distribute working documents as Internet-
+   Drafts.
+
+   Internet-Drafts are draft documents valid for a maximum of six months
+   and may be updated, replaced, or obsoleted by other documents at any
+   time.  It is inappropriate to use Internet-Drafts as reference
+   material or to cite them other than as "work in progress."
+
+   The list of current Internet-Drafts can be accessed at
+   http://www.ietf.org/ietf/1id-abstracts.txt.
+
+   The list of Internet-Draft Shadow Directories can be accessed at
+   http://www.ietf.org/shadow.html.
+
+   This Internet-Draft will expire on April 4, 2009.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Masarati                  Expires April 4, 2009                 [Page 1]
+
+Internet-Draft               LDAP WHATFAILED                October 2008
+
+
+Abstract
+
+   This document describes the LDAP "What Failed?" control.  This
+   control allows DUAs to request, in response to a failed operation
+   request, the object identifier of those extensions that caused the
+   operation to fail.
+
+
+Table of Contents
+
+   1.  Background and Intended Use  . . . . . . . . . . . . . . . . .  3
+   2.  LDAP "What Failed?" Control  . . . . . . . . . . . . . . . . .  4
+     2.1.  Control Semantics  . . . . . . . . . . . . . . . . . . . .  4
+     2.2.  Control Request  . . . . . . . . . . . . . . . . . . . . .  4
+     2.3.  Control Response . . . . . . . . . . . . . . . . . . . . .  5
+   3.  Implementation Notes . . . . . . . . . . . . . . . . . . . . .  6
+   4.  Security Considerations  . . . . . . . . . . . . . . . . . . .  7
+   5.  IANA Considerations  . . . . . . . . . . . . . . . . . . . . .  8
+     5.1.  Object Identifier Registration . . . . . . . . . . . . . .  8
+   6.  Acknowledgments  . . . . . . . . . . . . . . . . . . . . . . .  9
+   7.  References . . . . . . . . . . . . . . . . . . . . . . . . . . 10
+     7.1.  Normative References . . . . . . . . . . . . . . . . . . . 10
+     7.2.  Informative References . . . . . . . . . . . . . . . . . . 10
+   Author's Address . . . . . . . . . . . . . . . . . . . . . . . . . 11
+   Intellectual Property and Copyright Statements . . . . . . . . . . 12
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Masarati                  Expires April 4, 2009                 [Page 2]
+
+Internet-Draft               LDAP WHATFAILED                October 2008
+
+
+1.  Background and Intended Use
+
+   The LDAP Protocol [RFC4510] is extensible.  Extensions include
+   controls, extended requests and extensions related to other aspects
+   of the protocol, for example those described in [RFC4526], [RFC4529]
+   and more.
+
+   Operations may fail for different reasons.  The resultCode may help
+   in determining the reason of a failure.  The (optional)
+   diagnosticsMessage fields of a LDAPResponse could also be of help.
+   However, according to [RFC4511], implementations MUST NOT rely on the
+   returned values, which are simply intended to be presented as are to
+   human users.
+
+   In case of failure related to the inability to process a control
+   marked as critical in a request, the specific resultCode
+   unavailableCriticalExtension is returned.  In case of failure related
+   to an unrecognized extendedReq, the generic resultCode protocolError
+   is returned.  Failures related to handling other extensions may
+   result in other generic resultCode values.
+
+   As a consequence, DUAs may be unable to exactly determine what
+   extension, if any, caused a failure.  The "What Failed?" control
+   represents a means for the DSA to inform DUAs about what specific
+   extensions, if any, caused an error notified by the DSA.
+
+   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+   document are to be interpreted as described in [RFC2119].
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Masarati                  Expires April 4, 2009                 [Page 3]
+
+Internet-Draft               LDAP WHATFAILED                October 2008
+
+
+2.  LDAP "What Failed?" Control
+
+2.1.  Control Semantics
+
+   The presence of the "What Failed?"  LDAP control in a LDAP request
+   indicates that the DUA, in case of error, wishes to receive detailed
+   information about what extension, if any, caused the error.
+
+   The criticality of the control in the request SHOULD be FALSE.
+   According to the semantics of the criticality field as indicated in
+   [RFC4511], this ensures that in case the control is not recognized by
+   the DSA, it does not cause itself an error.
+
+   The presence of this control in a request does not guarantee that the
+   DSA will return detailed information about what extensions caused an
+   error.  Considering the requirement on the criticality of the
+   control, the DSA MAY simply choose to ignore the control.  The DSA
+   MAY hide information about failure in handling an extension to
+   prevent disclosure of other information.  The DSA MAY choose to
+   notify an error as soon as it is detected, instead of proceed
+   checking its ability to handle any other extension present in a
+   request.
+
+   Implementations may choose to check the validity of extensions,
+   including controls, as soon as they are parsed.  As a consequence, a
+   critical control might result in an error before thw "What Failed?"
+   control request is parsed.  Implementations SHOULD check anyway the
+   presence of this control, unless they detect that the remaining part
+   of the request is malformed.  Clients SHOULD NOT rely on any specific
+   ordering of controls handling when requesting the "What Failed?"
+   control.
+
+   Servers implementing this technical specification SHOULD publish the
+   object identifier whatFailed-oid (IANA assigned; see Section 5) as a
+   value of the 'supportedControl' attribute [RFC4512] in their root
+   DSE.
+
+2.2.  Control Request
+
+   The controlType is whatFailed-oid (IANA assigned; see Section 5); the
+   controlValue MUST be absent; the criticality SHOULD be FALSE.
+
+
+
+
+
+
+
+
+
+
+Masarati                  Expires April 4, 2009                 [Page 4]
+
+Internet-Draft               LDAP WHATFAILED                October 2008
+
+
+2.3.  Control Response
+
+   The controlType is whatFailed-oid (IANA assigned; see Section 5); the
+   controlValue is:
+
+       controlValue ::= SET OF oid LDAPOID
+
+   If the set of extension OID is empty, the control is omitted from the
+   response.  The criticality MUST be FALSE.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Masarati                  Expires April 4, 2009                 [Page 5]
+
+Internet-Draft               LDAP WHATFAILED                October 2008
+
+
+3.  Implementation Notes
+
+   The "What Failed?"  LDAP Control is implemented in OpenLDAP software
+   using the temporary OID 1.3.6.1.4.1.4203.666.5.17 under OpenLDAP's
+   experimental OID arc.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Masarati                  Expires April 4, 2009                 [Page 6]
+
+Internet-Draft               LDAP WHATFAILED                October 2008
+
+
+4.  Security Considerations
+
+   Implementations MUST take measures to prevent the disclosure of
+   sensible information whenever this may result from disclosing what
+   extension caused an error.  This can consist in excluding the OID of
+   specific extensions from the controlValue in the response, or in
+   entirely omitting the control in the response.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Masarati                  Expires April 4, 2009                 [Page 7]
+
+Internet-Draft               LDAP WHATFAILED                October 2008
+
+
+5.  IANA Considerations
+
+5.1.  Object Identifier Registration
+
+   It is requested that IANA register upon Standards Action an LDAP
+   Object Identifier for use in this technical specification.
+
+         Subject: Request for LDAP OID Registration
+         Person & email address to contact for further information:
+             Pierangelo Masarati <ando@OpenLDAP.org>
+         Specification: (I-D)
+         Author/Change Controller: IESG
+         Comments:
+             Identifies the LDAP "What Failed?" Control request
+             and response
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Masarati                  Expires April 4, 2009                 [Page 8]
+
+Internet-Draft               LDAP WHATFAILED                October 2008
+
+
+6.  Acknowledgments
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Masarati                  Expires April 4, 2009                 [Page 9]
+
+Internet-Draft               LDAP WHATFAILED                October 2008
+
+
+7.  References
+
+7.1.  Normative References
+
+   [RFC2119]  Bradner, S., "Key words for use in RFCs to Indicate
+              Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+   [RFC4510]  Zeilenga, K., "Lightweight Directory Access Protocol
+              (LDAP): Technical Specification Road Map", RFC 4510,
+              June 2006.
+
+   [RFC4511]  Sermersheim, J., "Lightweight Directory Access Protocol
+              (LDAP): The Protocol", RFC 4511, June 2006.
+
+   [RFC4512]  Zeilenga, K., "Lightweight Directory Access Protocol
+              (LDAP): Directory Information Models", RFC 4512,
+              June 2006.
+
+7.2.  Informative References
+
+   [RFC4526]  Zeilenga, K., "Lightweight Directory Access Protocol
+              (LDAP) Absolute True and False Filters", RFC 4526,
+              June 2006.
+
+   [RFC4529]  Zeilenga, K., "Requesting Attributes by Object Class in
+              the Lightweight Directory Access Protocol", RFC 4529,
+              June 2006.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Masarati                  Expires April 4, 2009                [Page 10]
+
+Internet-Draft               LDAP WHATFAILED                October 2008
+
+
+Author's Address
+
+   Pierangelo Masarati
+   Politecnico di Milano
+   Dipartimento di Ingegneria Aerospaziale
+   via La Masa 34
+   Milano  20156
+   IT
+
+   Phone: +39 02 2399 8309
+   Fax:   +39 02 2399 8334
+   Email: ando@OpenLDAP.org
+   URI:   http://www.aero.polimi.it/masarati/
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Masarati                  Expires April 4, 2009                [Page 11]
+
+Internet-Draft               LDAP WHATFAILED                October 2008
+
+
+Full Copyright Statement
+
+   Copyright (C) The IETF Trust (2008).
+
+   This document is subject to the rights, licenses and restrictions
+   contained in BCP 78, and except as set forth therein, the authors
+   retain all their rights.
+
+   This document and the information contained herein are provided on an
+   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
+   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND
+   THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF
+   THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
+   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+
+Intellectual Property
+
+   The IETF takes no position regarding the validity or scope of any
+   Intellectual Property Rights or other rights that might be claimed to
+   pertain to the implementation or use of the technology described in
+   this document or the extent to which any license under such rights
+   might or might not be available; nor does it represent that it has
+   made any independent effort to identify any such rights.  Information
+   on the procedures with respect to rights in RFC documents can be
+   found in BCP 78 and BCP 79.
+
+   Copies of IPR disclosures made to the IETF Secretariat and any
+   assurances of licenses to be made available, or the result of an
+   attempt made to obtain a general license or permission for the use of
+   such proprietary rights by implementers or users of this
+   specification can be obtained from the IETF on-line IPR repository at
+   http://www.ietf.org/ipr.
+
+   The IETF invites any interested party to bring to its attention any
+   copyrights, patents or patent applications, or other proprietary
+   rights that may cover technology that may be required to implement
+   this standard.  Please address the information to the IETF at
+   ietf-ipr@ietf.org.
+
+
+
+
+
+
+
+
+
+
+
+Masarati                  Expires April 4, 2009                [Page 12]
+
diff --git a/doc/drafts/draft-masarati-ldap-whatfailed.xml b/doc/drafts/draft-masarati-ldap-whatfailed.xml
new file mode 100644
index 0000000000..1d8ce5e470
--- /dev/null
+++ b/doc/drafts/draft-masarati-ldap-whatfailed.xml
@@ -0,0 +1,240 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!DOCTYPE rfc SYSTEM "rfc2629.dtd" [
+    <!ENTITY rfc2119 PUBLIC '' 
+      'http://xml.resource.org/public/rfc/bibxml/reference.RFC.2119.xml'>
+    <!ENTITY rfc4510 PUBLIC '' 
+      'http://xml.resource.org/public/rfc/bibxml/reference.RFC.4510.xml'>
+    <!ENTITY rfc4511 PUBLIC '' 
+      'http://xml.resource.org/public/rfc/bibxml/reference.RFC.4511.xml'>
+    <!ENTITY rfc4512 PUBLIC '' 
+      'http://xml.resource.org/public/rfc/bibxml/reference.RFC.4512.xml'>
+    <!ENTITY rfc4526 PUBLIC '' 
+      'http://xml.resource.org/public/rfc/bibxml/reference.RFC.4526.xml'>
+    <!ENTITY rfc4529 PUBLIC '' 
+      'http://xml.resource.org/public/rfc/bibxml/reference.RFC.4529.xml'>
+]>
+
+<!-- $OpenLDAP$ -->
+
+<rfc category="std" ipr="full3978" docName="draft-masarati-ldap-whatfailed.txt">
+
+<?xml-stylesheet type='text/xsl' href='rfc2629.xslt' ?>
+
+<?rfc toc="yes" ?>
+<?rfc symrefs="yes" ?>
+<?rfc sortrefs="yes"?>
+<?rfc iprnotified="no" ?>
+<?rfc strict="yes" ?>
+
+    <front>
+        <title abbrev='LDAP WHATFAILED'>LDAP "What Failed?" Control</title>
+        <author initials='P.' surname="Masarati" fullname='Pierangelo Masarati'>
+            <organization abbrev='Politecnico di Milano'>
+                Politecnico di Milano
+            </organization>
+            <address>
+                <postal>
+                    <street>Dipartimento di Ingegneria Aerospaziale</street>
+                    <street>via La Masa 34</street>
+                    <city>Milano</city>
+                    <code>20156</code>
+                    <country>IT</country>
+                </postal>
+                <phone>+39 02 2399 8309</phone>
+                <facsimile>+39 02 2399 8334</facsimile>
+                <email>ando@OpenLDAP.org</email>
+                <uri>http://www.aero.polimi.it/masarati/</uri>
+            </address>
+        </author>
+        <!--date/-->
+        <date month='October' year='2008' />
+        <abstract>
+            <t>
+This document describes the LDAP "What Failed?" control.
+This control allows DUAs to request, in response to a failed operation
+request, the object identifier of those extensions that caused
+the operation to fail.
+            </t>
+        </abstract>
+    </front>
+
+    <middle>
+        <section title="Background and Intended Use">
+            <t>
+The LDAP Protocol <xref target="RFC4510" /> is extensible.
+Extensions include controls, extended requests and extensions related
+to other aspects of the protocol, for example those described in
+<xref target="RFC4526" />, <xref target="RFC4529" /> and more.
+            </t>
+
+            <t>
+Operations may fail for different reasons.
+The resultCode may help in determining the reason of a failure.
+The (optional) diagnosticsMessage fields of a LDAPResponse
+could also be of help.
+However, according to <xref target="RFC4511" />,
+implementations MUST NOT rely on the returned values,
+which are simply intended to be presented as are to human users.
+            </t>
+
+            <t>
+In case of failure related to the inability to process a control
+marked as critical in a request, the specific resultCode
+unavailableCriticalExtension is returned.
+In case of failure related to an unrecognized extendedReq, the generic
+resultCode protocolError is returned.
+Failures related to handling other extensions may result 
+in other generic resultCode values.
+            </t>
+
+            <t>
+As a consequence, DUAs may be unable to exactly determine
+what extension, if any, caused a failure.
+The "What Failed?" control represents a means for the DSA to inform
+DUAs about what specific extensions, if any, caused an error notified
+by the DSA.
+            </t>
+
+            <t>
+The key words "MUST", "MUST NOT", "REQUIRED", "SHALL",
+"SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY",
+and "OPTIONAL" in this document are to be interpreted as
+described in <xref target="RFC2119" />.
+            </t>
+        </section>
+
+        <section title='LDAP "What Failed?" Control'>
+            <section title="Control Semantics">
+                <t>
+The presence of the "What Failed?" LDAP control in a LDAP request
+indicates that the DUA, in case of error, wishes to receive detailed
+information about what extension, if any, caused the error.
+                </t>
+
+                <t>
+The criticality of the control in the request SHOULD be FALSE.
+According to the semantics of the criticality field as indicated
+in <xref target="RFC4511" />, this ensures that in case the control
+is not recognized by the DSA, it does not cause itself an error.
+                </t>
+
+                <t>
+The presence of this control in a request does not guarantee that the DSA
+will return detailed information about what extensions caused an error.
+Considering the requirement on the criticality of the control,
+the DSA MAY simply choose to ignore the control.
+The DSA MAY hide information about failure in handling an extension
+to prevent disclosure of other information.
+The DSA MAY choose to notify an error as soon as it is detected,
+instead of proceed checking its ability to handle any other extension
+present in a request.
+                </t>
+
+                <t>
+Implementations may choose to check the validity of extensions,
+including controls, as soon as they are parsed.
+As a consequence, a critical control might result in an error
+before thw "What Failed?" control request is parsed.
+Implementations SHOULD check anyway the presence of this control,
+unless they detect that the remaining part of the request
+is malformed.
+Clients SHOULD NOT rely on any specific ordering of controls handling
+when requesting the "What Failed?" control.
+                </t>
+
+                <t>
+Servers implementing this technical specification SHOULD publish
+the object identifier whatFailed-oid (IANA assigned;
+see <xref target="iana_considerations" />) as a value
+of the 'supportedControl' attribute <xref target="RFC4512" />
+in their root DSE.
+                </t>
+            </section>
+
+            <section title="Control Request">
+                <t>
+The controlType is whatFailed-oid (IANA assigned;
+see <xref target="iana_considerations" />);
+the controlValue MUST be absent;
+the criticality SHOULD be FALSE.
+                </t>
+            </section>
+
+            <section title="Control Response">
+                <figure>
+                    <preamble>
+The controlType is whatFailed-oid (IANA assigned;
+see <xref target="iana_considerations" />);
+the controlValue is:
+                    </preamble>
+                    <artwork>
+    controlValue ::= SET OF oid LDAPOID
+                    </artwork>
+                    <postamble>
+If the set of extension OID is empty, the control is omitted
+from the response.
+The criticality MUST be FALSE.
+                    </postamble>
+                </figure>
+            </section>
+        </section>
+
+        <section title="Implementation Notes">
+            <t>
+The "What Failed?" LDAP Control is implemented in OpenLDAP software
+using the temporary OID 1.3.6.1.4.1.4203.666.5.17 under OpenLDAP's
+experimental OID arc.
+            </t>
+        </section>
+
+        <section title="Security Considerations">
+            <t>
+Implementations MUST take measures to prevent the disclosure
+of sensible information whenever this may result from disclosing
+what extension caused an error.
+This can consist in excluding the OID of specific extensions from
+the controlValue in the response, or in entirely omitting the control
+in the response.
+            </t>
+        </section>
+
+        <section anchor="iana_considerations" title="IANA Considerations">
+            <section title="Object Identifier Registration">
+                <figure>
+                    <preamble>
+It is requested that IANA register upon Standards Action an LDAP
+Object Identifier for use in this technical specification.
+                    </preamble>
+                    <artwork>
+      Subject: Request for LDAP OID Registration
+      Person &amp; email address to contact for further information:
+          Pierangelo Masarati &lt;ando@OpenLDAP.org&gt;
+      Specification: (I-D)
+      Author/Change Controller: IESG
+      Comments:
+          Identifies the LDAP "What Failed?" Control request
+          and response
+                    </artwork>
+                </figure>
+            </section>
+        </section>
+
+        <section title="Acknowledgments">
+        </section>
+    </middle>
+
+    <back>
+        <references title='Normative References'>
+            &rfc2119;
+            &rfc4510;
+            &rfc4511;
+            &rfc4512;
+        </references>
+        <references title='Informative References'>
+            &rfc4526;
+            &rfc4529;
+        </references>
+    </back>
+
+</rfc>
diff --git a/include/ldap.h b/include/ldap.h
index 99c2474723..59dd2e4539 100644
--- a/include/ldap.h
+++ b/include/ldap.h
@@ -323,6 +323,8 @@ typedef struct ldapcontrol {
 						LDAP_CONTROL_X_SESSION_TRACKING ".3"
 /* Dereference Control (work in progress) */
 #define	LDAP_CONTROL_X_DEREF			"1.3.6.1.4.1.4203.666.5.16"
+/* "What Failed?" Control (work in progress) */
+#define	LDAP_CONTROL_X_WHATFAILED		"1.3.6.1.4.1.4203.666.5.17"
 #endif /* LDAP_DEVEL */
 
 /* various expired works */
diff --git a/servers/slapd/backend.c b/servers/slapd/backend.c
index db3f299b61..ccbc938da5 100644
--- a/servers/slapd/backend.c
+++ b/servers/slapd/backend.c
@@ -946,6 +946,12 @@ backend_check_controls(
 
 			case LDAP_COMPARE_FALSE:
 				if ( !op->o_bd->be_ctrls[cid] && (*ctrls)->ldctl_iscritical ) {
+#ifdef SLAP_CONTROL_X_WHATFAILED
+					if ( get_whatFailed( op ) ) {
+						char *oids[ 2 ] = { (*ctrls)->ldctl_oid, NULL };
+						slap_ctrl_whatFailed_add( op, rs, oids );
+					}
+#endif
 					/* RFC 4511 allows unavailableCriticalExtension to be
 					 * returned when the server is unwilling to perform
 					 * an operation extended by a recognized critical
diff --git a/servers/slapd/controls.c b/servers/slapd/controls.c
index f2efdd1696..496524f10a 100644
--- a/servers/slapd/controls.c
+++ b/servers/slapd/controls.c
@@ -48,6 +48,9 @@ static SLAP_CTRL_PARSE_FN parseValuesReturnFilter;
 #ifdef SLAP_CONTROL_X_SESSION_TRACKING
 static SLAP_CTRL_PARSE_FN parseSessionTracking;
 #endif
+#ifdef SLAP_CONTROL_X_WHATFAILED
+static SLAP_CTRL_PARSE_FN parseWhatFailed;
+#endif
 
 #undef sc_mask /* avoid conflict with Irix 6.5 <sys/signal.h> */
 
@@ -217,6 +220,14 @@ static struct slap_control control_defs[] = {
 		session_tracking_extops, NULL,
 		parseSessionTracking, LDAP_SLIST_ENTRY_INITIALIZER(next) },
 #endif
+#ifdef SLAP_CONTROL_X_WHATFAILED
+	{ LDAP_CONTROL_X_WHATFAILED,
+ 		(int)offsetof(struct slap_control_ids, sc_whatFailed),
+		SLAP_CTRL_GLOBAL|SLAP_CTRL_ACCESS|SLAP_CTRL_HIDE,
+		NULL, NULL,
+		parseWhatFailed, LDAP_SLIST_ENTRY_INITIALIZER(next) },
+#endif
+
 	{ NULL, 0, 0, NULL, 0, NULL, LDAP_SLIST_ENTRY_INITIALIZER(next) }
 };
 
@@ -536,6 +547,7 @@ int slap_parse_ctrl(
 	const char **text )
 {
 	struct slap_control *sc;
+	int rc = LDAP_SUCCESS;
 
 	sc = find_ctrl( control->ldctl_oid );
 	if( sc != NULL ) {
@@ -591,31 +603,29 @@ int slap_parse_ctrl(
 
 		if (( sc->sc_mask & tagmask ) == tagmask ) {
 			/* available extension */
-			int	rc;
+			if ( sc->sc_parse ) {
+				rc = sc->sc_parse( op, rs, control );
+				assert( rc != LDAP_UNAVAILABLE_CRITICAL_EXTENSION );
 
-			if( !sc->sc_parse ) {
+			} else if ( control->ldctl_iscritical ) {
 				*text = "not yet implemented";
-				return LDAP_OTHER;
+				rc = LDAP_OTHER;
 			}
 
-			rc = sc->sc_parse( op, rs, control );
-			if ( rc ) {
-				assert( rc != LDAP_UNAVAILABLE_CRITICAL_EXTENSION );
-				return rc;
-			}
 
-		} else if( control->ldctl_iscritical ) {
+		} else if ( control->ldctl_iscritical ) {
 			/* unavailable CRITICAL control */
 			*text = "critical extension is unavailable";
-			return LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
+			rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
 		}
-	} else if( control->ldctl_iscritical ) {
+
+	} else if ( control->ldctl_iscritical ) {
 		/* unrecognized CRITICAL control */
 		*text = "critical extension is not recognized";
-		return LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
+		rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
 	}
 
-	return LDAP_SUCCESS;
+	return rc;
 }
 
 int get_ctrls(
@@ -629,6 +639,15 @@ int get_ctrls(
 	char *opaque;
 	BerElement *ber = op->o_ber;
 	struct berval bv;
+#ifdef SLAP_CONTROL_X_WHATFAILED
+	/* NOTE: right now, slapd checks the validity of each control
+	 * while parsing.  As a consequence, it can only detect one
+	 * cause of failure at a time.  This results in returning
+	 * exactly one OID with the whatFailed control, or no control
+	 * at all.
+	 */
+	char *failed_oid = NULL;
+#endif
 
 	len = ber_pvt_ber_remaining(ber);
 
@@ -769,6 +788,9 @@ int get_ctrls(
 
 		rs->sr_err = slap_parse_ctrl( op, rs, c, &rs->sr_text );
 		if ( rs->sr_err != LDAP_SUCCESS ) {
+#ifdef SLAP_CONTROL_X_WHATFAILED
+			failed_oid = c->ldctl_oid;
+#endif
 			goto return_results;
 		}
 	}
@@ -784,6 +806,69 @@ return_results:
 			send_ldap_disconnect( op, rs );
 			rs->sr_err = SLAPD_DISCONNECT;
 		} else {
+#ifdef SLAP_CONTROL_X_WHATFAILED
+			/* might have not been parsed yet? */
+			if ( failed_oid != NULL ) {
+				if ( !get_whatFailed( op ) ) {
+					/* look it up */
+
+					/* step through each remaining element */
+					for ( ; tag != LBER_ERROR; tag = ber_next_element( ber, &len, opaque ) )
+					{
+						LDAPControl c = { 0 };
+
+						tag = ber_scanf( ber, "{m" /*}*/, &bv );
+						c.ldctl_oid = bv.bv_val;
+
+						if ( tag == LBER_ERROR ) {
+							slap_free_ctrls( op, op->o_ctrls );
+							op->o_ctrls = NULL;
+							break;
+
+						} else if ( c.ldctl_oid == NULL ) {
+							slap_free_ctrls( op, op->o_ctrls );
+							op->o_ctrls = NULL;
+							break;
+						}
+
+						tag = ber_peek_tag( ber, &len );
+						if ( tag == LBER_BOOLEAN ) {
+							ber_int_t crit;
+							tag = ber_scanf( ber, "b", &crit );
+							if( tag == LBER_ERROR ) {
+								slap_free_ctrls( op, op->o_ctrls );
+								op->o_ctrls = NULL;
+								break;
+							}
+
+							tag = ber_peek_tag( ber, &len );
+						}
+
+						if ( tag == LBER_OCTETSTRING ) {
+							tag = ber_scanf( ber, "m", &c.ldctl_value );
+
+							if( tag == LBER_ERROR ) {
+								slap_free_ctrls( op, op->o_ctrls );
+								op->o_ctrls = NULL;
+								break;
+							}
+						}
+
+						if ( strcmp( c.ldctl_oid, LDAP_CONTROL_X_WHATFAILED ) == 0 ) {
+							const char *text;
+							slap_parse_ctrl( op, rs, &c, &text );
+							break;
+						}
+					}
+				}
+
+				if ( get_whatFailed( op ) ) {
+					char *oids[ 2 ] = { failed_oid, NULL };
+					slap_ctrl_whatFailed_add( op, rs, oids );
+				}
+			}
+#endif
+
 			send_ldap_result( op, rs );
 		}
 	}
@@ -1112,11 +1197,11 @@ static int parsePagedResults (
     If the page size is greater than or equal to the sizeLimit value, the
     server should ignore the control as the request can be satisfied in a
     single page.
-	 
+
 	 * NOTE: this assumes that the op->ors_slimit be set
 	 * before the controls are parsed.     
 	 */
-		
+
 	if ( op->ors_slimit > 0 && size >= op->ors_slimit ) {
 		op->o_pagedresults = SLAP_CONTROL_IGNORED;
 
@@ -1192,7 +1277,7 @@ static int parseAssert (
 		rs->sr_text = "assert control: internal error";
 		return LDAP_OTHER;
 	}
-	
+
 	rs->sr_err = get_filter( op, ber, (Filter **)&(op->o_assertion),
 		&rs->sr_text);
 	(void) ber_free( ber, 1 );
@@ -1377,7 +1462,7 @@ static int parseValuesReturnFilter (
 		rs->sr_text = "internal error";
 		return LDAP_OTHER;
 	}
-	
+
 	rs->sr_err = get_vrFilter( op, ber,
 		(ValuesReturnFilter **)&(op->o_vrFilter), &rs->sr_text);
 
@@ -1865,3 +1950,87 @@ slap_ctrl_session_tracking_request_add( Operation *op, SlapReply *rs, LDAPContro
 	return slap_ctrl_session_tracking_add( op, rs, &ip, &name, &id, ctrl );
 }
 #endif
+
+#ifdef SLAP_CONTROL_X_WHATFAILED
+static int parseWhatFailed(
+	Operation *op,
+	SlapReply *rs,
+	LDAPControl *ctrl )
+{
+	if ( op->o_whatFailed != SLAP_CONTROL_NONE ) {
+		rs->sr_text = "\"WHat Failed?\" control specified multiple times";
+		return LDAP_PROTOCOL_ERROR;
+	}
+
+	if ( !BER_BVISNULL( &ctrl->ldctl_value )) {
+		rs->sr_text = "\"What Failed?\" control value not absent";
+		return LDAP_PROTOCOL_ERROR;
+	}
+
+	op->o_whatFailed = ctrl->ldctl_iscritical
+		? SLAP_CONTROL_CRITICAL
+		: SLAP_CONTROL_NONCRITICAL;
+
+	return LDAP_SUCCESS;
+}
+
+int
+slap_ctrl_whatFailed_add(
+	Operation *op,
+	SlapReply *rs,
+	char **oids )
+{
+	BerElementBuffer berbuf;
+	BerElement *ber = (BerElement *) &berbuf;
+	LDAPControl **ctrls = NULL;
+	struct berval ctrlval;
+	int i, rc = LDAP_SUCCESS;
+
+	ber_init2( ber, NULL, LBER_USE_DER );
+	ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
+	ber_printf( ber, "[" /*]*/ );
+	for ( i = 0; oids[ i ] != NULL; i++ ) {
+		ber_printf( ber, "s", oids[ i ] );
+	}
+	ber_printf( ber, /*[*/ "]" );
+
+	if ( ber_flatten2( ber, &ctrlval, 0 ) == -1 ) {
+		rc = LDAP_OTHER;
+		goto done;
+	}
+
+	i = 0;
+	if ( rs->sr_ctrls != NULL ) {
+		for ( ; rs->sr_ctrls[ i ] != NULL; i++ ) {
+			if ( strcmp( rs->sr_ctrls[ i ]->ldctl_oid, LDAP_CONTROL_X_WHATFAILED ) != 0 ) {
+				/* TODO: add */
+				assert( 0 );
+			}
+		}
+	}
+
+	ctrls = op->o_tmprealloc( rs->sr_ctrls,
+			sizeof(LDAPControl *)*( i + 2 )
+			+ sizeof(LDAPControl)
+			+ ctrlval.bv_len + 1,
+			op->o_tmpmemctx );
+	if ( ctrls == NULL ) {
+		rc = LDAP_OTHER;
+		goto done;
+	}
+	ctrls[ i + 1 ] = NULL;
+	ctrls[ i ] = (LDAPControl *)&ctrls[ i + 2 ];
+	ctrls[ i ]->ldctl_oid = LDAP_CONTROL_X_WHATFAILED;
+	ctrls[ i ]->ldctl_iscritical = 0;
+	ctrls[ i ]->ldctl_value.bv_val = (char *)&ctrls[ i ][ 1 ];
+	AC_MEMCPY( ctrls[ i ]->ldctl_value.bv_val, ctrlval.bv_val, ctrlval.bv_len + 1 );
+	ctrls[ i ]->ldctl_value.bv_len = ctrlval.bv_len;
+
+	ber_free_buf( ber );
+
+	rs->sr_ctrls = ctrls;
+
+done:;
+	return rc;
+}
+#endif
diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h
index 42aa39fe5a..3999334aa3 100644
--- a/servers/slapd/proto-slap.h
+++ b/servers/slapd/proto-slap.h
@@ -660,6 +660,13 @@ LDAP_SLAPD_F (int)
 slap_ctrl_session_tracking_request_add LDAP_P((
 	Operation *op, SlapReply *rs, LDAPControl *ctrl ));
 #endif /* SLAP_CONTROL_X_SESSION_TRACKING */
+#ifdef SLAP_CONTROL_X_WHATFAILED
+LDAP_SLAPD_F (int)
+slap_ctrl_whatFailed_add LDAP_P((
+	Operation *op,
+	SlapReply *rs,
+	char **oids ));
+#endif /* SLAP_CONTROL_X_WHATFAILED */
 
 /*
  * config.c
diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h
index 50039b2369..d9cdccf5bd 100644
--- a/servers/slapd/slap.h
+++ b/servers/slapd/slap.h
@@ -64,6 +64,7 @@ LDAP_BEGIN_DECL
 #define LDAP_SYNC_TIMESTAMP
 #define SLAP_CONTROL_X_SORTEDRESULTS
 #define SLAP_CONTROL_X_SESSION_TRACKING
+#define SLAP_CONTROL_X_WHATFAILED
 #define SLAP_CONFIG_DELETE
 #endif
 
@@ -2404,6 +2405,9 @@ struct slap_control_ids {
 	int sc_sessionTracking;
 #endif
 	int sc_valuesReturnFilter;
+#ifdef SLAP_CONTROL_X_WHATFAILED
+	int sc_whatFailed;
+#endif
 };
 
 /*
@@ -2673,6 +2677,11 @@ struct Operation {
 #define get_sessionTracking(op)			((int)(op)->o_session_tracking)
 #endif
 
+#ifdef SLAP_CONTROL_X_WHATFAILED
+#define o_whatFailed o_ctrlflag[slap_cids.sc_whatFailed]
+#define get_whatFailed(op)				_SCM((op)->o_whatFailed)
+#endif
+
 #define o_sync			o_ctrlflag[slap_cids.sc_LDAPsync]
 
 	AuthorizationInformation o_authz;
-- 
GitLab