1/* $OpenLDAP$ */
2/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3 *
4 * Copyright 1998-2011 The OpenLDAP Foundation.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted only as authorized by the OpenLDAP
9 * Public License.
10 *
11 * A copy of this license is available in the file LICENSE in the
12 * top-level directory of the distribution or, alternatively, at
13 * <http://www.OpenLDAP.org/license.html>.
14 */
15
16#include "portable.h"
17
18#include <stdio.h>
19
20#include <ac/stdlib.h>
21
22#include <ac/socket.h>
23#include <ac/string.h>
24#include <ac/time.h>
25
26#include "ldap-int.h"
27
28void ldap_int_error_init( void ) {
29}
30
31char *
32ldap_err2string( int err )
33{
34	char *m;
35
36	Debug( LDAP_DEBUG_TRACE, "ldap_err2string\n", 0, 0, 0 );
37
38	switch ( err ) {
39#	define C(code, message) case code: m = message; break
40
41	/* LDAPv3 (RFC 4511) codes */
42	C(LDAP_SUCCESS,					N_("Success"));
43	C(LDAP_OPERATIONS_ERROR, 		N_("Operations error"));
44	C(LDAP_PROTOCOL_ERROR, 			N_("Protocol error"));
45	C(LDAP_TIMELIMIT_EXCEEDED,		N_("Time limit exceeded"));
46	C(LDAP_SIZELIMIT_EXCEEDED, 		N_("Size limit exceeded"));
47	C(LDAP_COMPARE_FALSE, 			N_("Compare False"));
48	C(LDAP_COMPARE_TRUE, 			N_("Compare True"));
49	C(LDAP_STRONG_AUTH_NOT_SUPPORTED,N_("Authentication method not supported"));
50	C(LDAP_STRONG_AUTH_REQUIRED,	N_("Strong(er) authentication required"));
51
52	C(LDAP_REFERRAL,				N_("Referral"));
53	C(LDAP_ADMINLIMIT_EXCEEDED,		N_("Administrative limit exceeded"));
54	C(LDAP_UNAVAILABLE_CRITICAL_EXTENSION,
55									N_("Critical extension is unavailable"));
56	C(LDAP_CONFIDENTIALITY_REQUIRED,N_("Confidentiality required"));
57	C(LDAP_SASL_BIND_IN_PROGRESS,	N_("SASL bind in progress"));
58
59	C(LDAP_NO_SUCH_ATTRIBUTE, 		N_("No such attribute"));
60	C(LDAP_UNDEFINED_TYPE, 			N_("Undefined attribute type"));
61	C(LDAP_INAPPROPRIATE_MATCHING, 	N_("Inappropriate matching"));
62	C(LDAP_CONSTRAINT_VIOLATION, 	N_("Constraint violation"));
63	C(LDAP_TYPE_OR_VALUE_EXISTS, 	N_("Type or value exists"));
64	C(LDAP_INVALID_SYNTAX, 			N_("Invalid syntax"));
65
66	C(LDAP_NO_SUCH_OBJECT, 			N_("No such object"));
67	C(LDAP_ALIAS_PROBLEM, 			N_("Alias problem"));
68	C(LDAP_INVALID_DN_SYNTAX,		N_("Invalid DN syntax"));
69
70	C(LDAP_ALIAS_DEREF_PROBLEM,	 	N_("Alias dereferencing problem"));
71
72	C(LDAP_INAPPROPRIATE_AUTH, 		N_("Inappropriate authentication"));
73	C(LDAP_INVALID_CREDENTIALS, 	N_("Invalid credentials"));
74	C(LDAP_INSUFFICIENT_ACCESS, 	N_("Insufficient access"));
75	C(LDAP_BUSY, 					N_("Server is busy"));
76	C(LDAP_UNAVAILABLE, 			N_("Server is unavailable"));
77	C(LDAP_UNWILLING_TO_PERFORM, 	N_("Server is unwilling to perform"));
78	C(LDAP_LOOP_DETECT, 			N_("Loop detected"));
79
80	C(LDAP_NAMING_VIOLATION, 		N_("Naming violation"));
81	C(LDAP_OBJECT_CLASS_VIOLATION, 	N_("Object class violation"));
82	C(LDAP_NOT_ALLOWED_ON_NONLEAF, 	N_("Operation not allowed on non-leaf"));
83	C(LDAP_NOT_ALLOWED_ON_RDN,	 	N_("Operation not allowed on RDN"));
84	C(LDAP_ALREADY_EXISTS, 			N_("Already exists"));
85	C(LDAP_NO_OBJECT_CLASS_MODS, 	N_("Cannot modify object class"));
86
87	C(LDAP_AFFECTS_MULTIPLE_DSAS,	N_("Operation affects multiple DSAs"));
88
89	/* Virtual List View draft */
90	C(LDAP_VLV_ERROR,				N_("Virtual List View error"));
91
92	C(LDAP_OTHER, N_("Other (e.g., implementation specific) error"));
93
94	/* LDAPv2 (RFC 1777) codes */
95	C(LDAP_PARTIAL_RESULTS, N_("Partial results and referral received"));
96	C(LDAP_IS_LEAF, 				N_("Entry is a leaf"));
97
98	/* Connection-less LDAP (CLDAP - RFC 1798) code */
99	C(LDAP_RESULTS_TOO_LARGE,		N_("Results too large"));
100
101	/* Cancel Operation (RFC 3909) codes */
102	C(LDAP_CANCELLED,				N_("Cancelled"));
103	C(LDAP_NO_SUCH_OPERATION,		N_("No Operation to Cancel"));
104	C(LDAP_TOO_LATE,				N_("Too Late to Cancel"));
105	C(LDAP_CANNOT_CANCEL,			N_("Cannot Cancel"));
106
107	/* Assert Control (RFC 4528 and old internet-draft) codes */
108	C(LDAP_ASSERTION_FAILED,		N_("Assertion Failed"));
109	C(LDAP_X_ASSERTION_FAILED,		N_("Assertion Failed (X)"));
110
111	/* Proxied Authorization Control (RFC 4370 and I-D) codes */
112	C(LDAP_PROXIED_AUTHORIZATION_DENIED, N_("Proxied Authorization Denied"));
113	C(LDAP_X_PROXY_AUTHZ_FAILURE,	N_("Proxy Authorization Failure (X)"));
114
115	/* Content Sync Operation (RFC 4533 and I-D) codes */
116	C(LDAP_SYNC_REFRESH_REQUIRED,	N_("Content Sync Refresh Required"));
117	C(LDAP_X_SYNC_REFRESH_REQUIRED,	N_("Content Sync Refresh Required (X)"));
118
119	/* No-Op Control (draft-zeilenga-ldap-noop) code */
120	C(LDAP_X_NO_OPERATION,			N_("No Operation (X)"));
121
122	/* Client Update Protocol (RFC 3928) codes */
123	C(LDAP_CUP_RESOURCES_EXHAUSTED,	N_("LCUP Resources Exhausted"));
124	C(LDAP_CUP_SECURITY_VIOLATION,	N_("LCUP Security Violation"));
125	C(LDAP_CUP_INVALID_DATA,		N_("LCUP Invalid Data"));
126	C(LDAP_CUP_UNSUPPORTED_SCHEME,	N_("LCUP Unsupported Scheme"));
127	C(LDAP_CUP_RELOAD_REQUIRED,		N_("LCUP Reload Required"));
128
129#ifdef LDAP_X_TXN
130	/* Codes related to LDAP Transactions (draft-zeilenga-ldap-txn) */
131	C(LDAP_X_TXN_SPECIFY_OKAY,		N_("TXN specify okay"));
132	C(LDAP_X_TXN_ID_INVALID,		N_("TXN ID is invalid"));
133#endif
134
135	/* API codes - renumbered since draft-ietf-ldapext-ldap-c-api */
136	C(LDAP_SERVER_DOWN,				N_("Can't contact LDAP server"));
137	C(LDAP_LOCAL_ERROR,				N_("Local error"));
138	C(LDAP_ENCODING_ERROR,			N_("Encoding error"));
139	C(LDAP_DECODING_ERROR,			N_("Decoding error"));
140	C(LDAP_TIMEOUT,					N_("Timed out"));
141	C(LDAP_AUTH_UNKNOWN,			N_("Unknown authentication method"));
142	C(LDAP_FILTER_ERROR,			N_("Bad search filter"));
143	C(LDAP_USER_CANCELLED,			N_("User cancelled operation"));
144	C(LDAP_PARAM_ERROR,				N_("Bad parameter to an ldap routine"));
145	C(LDAP_NO_MEMORY,				N_("Out of memory"));
146	C(LDAP_CONNECT_ERROR,			N_("Connect error"));
147	C(LDAP_NOT_SUPPORTED,			N_("Not Supported"));
148	C(LDAP_CONTROL_NOT_FOUND,		N_("Control not found"));
149	C(LDAP_NO_RESULTS_RETURNED,		N_("No results returned"));
150	C(LDAP_MORE_RESULTS_TO_RETURN,	N_("More results to return"));
151	C(LDAP_CLIENT_LOOP,				N_("Client Loop"));
152	C(LDAP_REFERRAL_LIMIT_EXCEEDED,	N_("Referral Limit Exceeded"));
153#	undef C
154
155	default:
156		m = (LDAP_API_ERROR(err) ? N_("Unknown API error")
157			 : LDAP_E_ERROR(err) ? N_("Unknown (extension) error")
158			 : LDAP_X_ERROR(err) ? N_("Unknown (private extension) error")
159			 : N_("Unknown error"));
160		break;
161	}
162
163	return _(m);
164}
165
166/* deprecated */
167void
168ldap_perror( LDAP *ld, LDAP_CONST char *str )
169{
170    int i;
171
172	assert( ld != NULL );
173	assert( LDAP_VALID( ld ) );
174	assert( str != NULL );
175
176	fprintf( stderr, "%s: %s (%d)\n",
177		str ? str : "ldap_perror",
178		ldap_err2string( ld->ld_errno ),
179		ld->ld_errno );
180
181	if ( ld->ld_matched != NULL && ld->ld_matched[0] != '\0' ) {
182		fprintf( stderr, _("\tmatched DN: %s\n"), ld->ld_matched );
183	}
184
185	if ( ld->ld_error != NULL && ld->ld_error[0] != '\0' ) {
186		fprintf( stderr, _("\tadditional info: %s\n"), ld->ld_error );
187	}
188
189	if ( ld->ld_referrals != NULL && ld->ld_referrals[0] != NULL) {
190		fprintf( stderr, _("\treferrals:\n") );
191		for (i=0; ld->ld_referrals[i]; i++) {
192			fprintf( stderr, _("\t\t%s\n"), ld->ld_referrals[i] );
193		}
194	}
195
196	fflush( stderr );
197}
198
199/* deprecated */
200int
201ldap_result2error( LDAP *ld, LDAPMessage *r, int freeit )
202{
203	int rc, err;
204
205	rc = ldap_parse_result( ld, r, &err,
206		NULL, NULL, NULL, NULL, freeit );
207
208	return err != LDAP_SUCCESS ? err : rc;
209}
210
211/*
212 * Parse LDAPResult Messages:
213 *
214 *   LDAPResult ::= SEQUENCE {
215 *     resultCode      ENUMERATED,
216 *     matchedDN       LDAPDN,
217 *     errorMessage    LDAPString,
218 *     referral        [3] Referral OPTIONAL }
219 *
220 * including Bind results:
221 *
222 *   BindResponse ::= [APPLICATION 1] SEQUENCE {
223 *     COMPONENTS OF LDAPResult,
224 *     serverSaslCreds  [7] OCTET STRING OPTIONAL }
225 *
226 * and ExtendedOp results:
227 *
228 *   ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
229 *     COMPONENTS OF LDAPResult,
230 *     responseName     [10] LDAPOID OPTIONAL,
231 *     response         [11] OCTET STRING OPTIONAL }
232 *
233 */
234int
235ldap_parse_result(
236	LDAP			*ld,
237	LDAPMessage		*r,
238	int				*errcodep,
239	char			**matcheddnp,
240	char			**errmsgp,
241	char			***referralsp,
242	LDAPControl		***serverctrls,
243	int				freeit )
244{
245	LDAPMessage	*lm;
246	ber_int_t errcode = LDAP_SUCCESS;
247
248	ber_tag_t tag;
249	BerElement	*ber;
250
251	Debug( LDAP_DEBUG_TRACE, "ldap_parse_result\n", 0, 0, 0 );
252
253	assert( ld != NULL );
254	assert( LDAP_VALID( ld ) );
255	assert( r != NULL );
256
257	if(errcodep != NULL) *errcodep = LDAP_SUCCESS;
258	if(matcheddnp != NULL) *matcheddnp = NULL;
259	if(errmsgp != NULL) *errmsgp = NULL;
260	if(referralsp != NULL) *referralsp = NULL;
261	if(serverctrls != NULL) *serverctrls = NULL;
262
263	LDAP_MUTEX_LOCK( &ld->ld_res_mutex );
264	/* Find the result, last msg in chain... */
265	lm = r->lm_chain_tail;
266	/* FIXME: either this is not possible (assert?)
267	 * or it should be handled */
268	if ( lm != NULL ) {
269		switch ( lm->lm_msgtype ) {
270		case LDAP_RES_SEARCH_ENTRY:
271		case LDAP_RES_SEARCH_REFERENCE:
272		case LDAP_RES_INTERMEDIATE:
273			lm = NULL;
274			break;
275
276		default:
277			break;
278		}
279	}
280
281	if( lm == NULL ) {
282		errcode = ld->ld_errno = LDAP_NO_RESULTS_RETURNED;
283		LDAP_MUTEX_UNLOCK( &ld->ld_res_mutex );
284	    goto done;
285	}
286
287	if ( ld->ld_error ) {
288		LDAP_FREE( ld->ld_error );
289		ld->ld_error = NULL;
290	}
291	if ( ld->ld_matched ) {
292		LDAP_FREE( ld->ld_matched );
293		ld->ld_matched = NULL;
294	}
295	if ( ld->ld_referrals ) {
296		LDAP_VFREE( ld->ld_referrals );
297		ld->ld_referrals = NULL;
298	}
299
300	/* parse results */
301
302	ber = ber_dup( lm->lm_ber );
303
304	if ( ld->ld_version < LDAP_VERSION2 ) {
305		tag = ber_scanf( ber, "{iA}",
306			&ld->ld_errno, &ld->ld_error );
307
308	} else {
309		ber_len_t len;
310
311		tag = ber_scanf( ber, "{iAA" /*}*/,
312			&ld->ld_errno, &ld->ld_matched, &ld->ld_error );
313
314		if( tag != LBER_ERROR ) {
315			/* peek for referrals */
316			if( ber_peek_tag(ber, &len) == LDAP_TAG_REFERRAL ) {
317				tag = ber_scanf( ber, "v", &ld->ld_referrals );
318			}
319		}
320
321		/* need to clean out misc items */
322		if( tag != LBER_ERROR ) {
323			if( lm->lm_msgtype == LDAP_RES_BIND ) {
324				/* look for sasl result creditials */
325				if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SASL_RES_CREDS ) {
326					/* skip 'em */
327					tag = ber_scanf( ber, "x" );
328				}
329
330			} else if( lm->lm_msgtype == LDAP_RES_EXTENDED ) {
331				/* look for exop result oid or value */
332				if ( ber_peek_tag( ber, &len ) == LDAP_TAG_EXOP_RES_OID ) {
333					/* skip 'em */
334					tag = ber_scanf( ber, "x" );
335				}
336
337				if ( tag != LBER_ERROR &&
338					ber_peek_tag( ber, &len ) == LDAP_TAG_EXOP_RES_VALUE )
339				{
340					/* skip 'em */
341					tag = ber_scanf( ber, "x" );
342				}
343			}
344		}
345
346		if( tag != LBER_ERROR ) {
347			int rc = ldap_pvt_get_controls( ber, serverctrls );
348
349			if( rc != LDAP_SUCCESS ) {
350				tag = LBER_ERROR;
351			}
352		}
353
354		if( tag != LBER_ERROR ) {
355			tag = ber_scanf( ber, /*{*/"}" );
356		}
357	}
358
359	if ( tag == LBER_ERROR ) {
360		ld->ld_errno = errcode = LDAP_DECODING_ERROR;
361	}
362
363	if( ber != NULL ) {
364		ber_free( ber, 0 );
365	}
366
367	/* return */
368	if( errcodep != NULL ) {
369		*errcodep = ld->ld_errno;
370	}
371	if ( errcode == LDAP_SUCCESS ) {
372		if( matcheddnp != NULL ) {
373			if ( ld->ld_matched )
374			{
375				*matcheddnp = LDAP_STRDUP( ld->ld_matched );
376			}
377		}
378		if( errmsgp != NULL ) {
379			if ( ld->ld_error )
380			{
381				*errmsgp = LDAP_STRDUP( ld->ld_error );
382			}
383		}
384
385		if( referralsp != NULL) {
386			*referralsp = ldap_value_dup( ld->ld_referrals );
387		}
388	}
389	LDAP_MUTEX_UNLOCK( &ld->ld_res_mutex );
390
391done:
392	if ( freeit ) {
393		ldap_msgfree( r );
394	}
395
396	return errcode;
397}
398