compare.c 5.99 KB
Newer Older
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1
2
3
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
4
 * Copyright 1999-2004 The OpenLDAP Foundation.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
5
6
 * Portions Copyright 2001-2003 Pierangelo Masarati.
 * Portions Copyright 1999-2003 Howard Chu.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
7
 * All rights reserved.
Pierangelo Masarati's avatar
Pierangelo Masarati committed
8
 *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
9
10
11
12
13
14
15
16
17
18
19
20
21
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted only as authorized by the OpenLDAP
 * Public License.
 *
 * A copy of this license is available in the file LICENSE in the
 * top-level directory of the distribution or, alternatively, at
 * <http://www.OpenLDAP.org/license.html>.
 */
/* ACKNOWLEDGEMENTS:
 * This work was initially developed by the Howard Chu for inclusion
 * in OpenLDAP Software and subsequently enhanced by Pierangelo
 * Masarati.
 */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
22
23
24
25
26
27
28
29
30
31
32
33
34

#include "portable.h"

#include <stdio.h>

#include <ac/string.h>
#include <ac/socket.h>

#include "slap.h"
#include "../back-ldap/back-ldap.h"
#include "back-meta.h"

int
35
meta_back_compare( Operation *op, SlapReply *rs )
Pierangelo Masarati's avatar
Pierangelo Masarati committed
36
{
37
	struct metainfo	*li = ( struct metainfo * )op->o_bd->be_private;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
38
	struct metaconn *lc;
39
	struct metasingleconn *lsc;
40
	char *match = NULL, *err = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
41
	struct berval mmatch = BER_BVNULL;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
42
	int candidates = 0, last = 0, i, count = 0, rc;
43
       	int cres = LDAP_SUCCESS, rres = LDAP_SUCCESS;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
44
	int *msgid;
45
	dncookie dc;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
46

47
	lc = meta_back_getconn( op, rs, META_OP_ALLOW_MULTIPLE,
48
49
50
51
52
53
54
55
56
			&op->o_req_ndn, NULL );
	if ( !lc ) {
 		send_ldap_result( op, rs );
		return -1;
	}
	
	if ( !meta_back_dobind( lc, op ) ) {
		rs->sr_err = LDAP_OTHER;
 		send_ldap_result( op, rs );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
57
58
59
60
61
62
63
64
65
66
67
		return -1;
	}

	msgid = ch_calloc( sizeof( int ), li->ntargets );
	if ( msgid == NULL ) {
		return -1;
	}

	/*
	 * start an asynchronous compare for each candidate target
	 */
68
69
	dc.conn = op->o_conn;
	dc.rs = rs;
70
	dc.ctx = "compareDN";
71

72
	for ( i = 0, lsc = lc->conns; !META_LAST(lsc); ++i, ++lsc ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
73
		struct berval mdn = BER_BVNULL;
74
75
		struct berval mapped_attr = op->oq_compare.rs_ava->aa_desc->ad_cname;
		struct berval mapped_value = op->oq_compare.rs_ava->aa_value;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
76

77
		if ( lsc->candidate != META_CANDIDATE ) {
78
			msgid[ i ] = -1;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
79
80
81
82
83
84
			continue;
		}

		/*
		 * Rewrite the compare dn, if needed
		 */
85
86
87
88
89
90
91
92
		dc.rwmap = &li->targets[ i ]->rwmap;

		switch ( ldap_back_dn_massage( &dc, &op->o_req_dn, &mdn ) ) {
		case LDAP_UNWILLING_TO_PERFORM:
			rc = 1;
			goto finish;

		default:
Pierangelo Masarati's avatar
Pierangelo Masarati committed
93
94
95
96
97
98
			break;
		}

		/*
		 * if attr is objectClass, try to remap the value
		 */
99
		if ( op->oq_compare.rs_ava->aa_desc == slap_schema.si_ad_objectClass ) {
100
			ldap_back_map( &li->targets[ i ]->rwmap.rwm_oc,
101
102
					&op->oq_compare.rs_ava->aa_value,
					&mapped_value, BACKLDAP_MAP );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
103

Pierangelo Masarati's avatar
Pierangelo Masarati committed
104
			if ( mapped_value.bv_val == NULL || mapped_value.bv_val[0] == '\0' ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
105
106
107
108
109
110
				continue;
			}
		/*
		 * else try to remap the attribute
		 */
		} else {
111
			ldap_back_map( &li->targets[ i ]->rwmap.rwm_at,
112
113
				&op->oq_compare.rs_ava->aa_desc->ad_cname,
				&mapped_attr, BACKLDAP_MAP );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
114
			if ( mapped_attr.bv_val == NULL || mapped_attr.bv_val[0] == '\0' ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
115
116
117
118
119
120
121
122
123
				continue;
			}
		}
		
		/*
		 * the compare op is spawned across the targets and the first
		 * that returns determines the result; a constraint on unicity
		 * of the result ought to be enforced
		 */
124
		msgid[ i ] = ldap_compare( lc->conns[ i ].ld, mdn.bv_val,
125
				mapped_attr.bv_val, mapped_value.bv_val );
126
127
128
		if ( mdn.bv_val != op->o_req_dn.bv_val ) {
			free( mdn.bv_val );
			mdn.bv_val = NULL;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
129
		}
130
		if ( mapped_attr.bv_val != op->oq_compare.rs_ava->aa_desc->ad_cname.bv_val ) {
131
			free( mapped_attr.bv_val );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
132
		}
133
		if ( mapped_value.bv_val != op->oq_compare.rs_ava->aa_value.bv_val ) {
134
			free( mapped_value.bv_val );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
135
136
		}

137
138
139
140
		if ( msgid[ i ] == -1 ) {
			continue;
		}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
141
142
143
144
145
146
147
148
149
150
151
		++candidates;
	}

	/*
	 * wait for replies
	 */
	for ( rc = 0, count = 0; candidates > 0; ) {

		/*
		 * FIXME: should we check for abandon?
		 */
152
		for ( i = 0, lsc = lc->conns; !META_LAST(lsc); lsc++, i++ ) {
153
154
			int		lrc;
			LDAPMessage	*res = NULL;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
155

156
			if ( msgid[ i ] == -1 ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
157
158
159
				continue;
			}

160
			lrc = ldap_result( lsc->ld, msgid[ i ],
Pierangelo Masarati's avatar
Pierangelo Masarati committed
161
162
163
164
165
166
167
168
169
170
					0, NULL, &res );

			if ( lrc == 0 ) {
				/*
				 * FIXME: should we yield?
				 */
				if ( res ) {
					ldap_msgfree( res );
				}
				continue;
171

Pierangelo Masarati's avatar
Pierangelo Masarati committed
172
173
			} else if ( lrc == LDAP_RES_COMPARE ) {
				if ( count > 0 ) {
174
					rres = LDAP_OTHER;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
175
176
177
178
					rc = -1;
					goto finish;
				}
				
179
180
				rs->sr_err = ldap_result2error( lsc->ld, res, 1 );
				switch ( rs->sr_err ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
181
182
183
184
185
186
187
188
				case LDAP_COMPARE_TRUE:
				case LDAP_COMPARE_FALSE:

					/*
					 * true or flase, got it;
					 * sending to cache ...
					 */
					if ( li->cache.ttl != META_DNCACHE_DISABLED ) {
189
						( void )meta_dncache_update_entry( &li->cache, &op->o_req_ndn, i );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
190
191
192
193
194
195
196
					}

					count++;
					rc = 0;
					break;

				default:
197
					rres = slap_map_api2result( rs );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
198
199
200
201

					if ( err != NULL ) {
						free( err );
					}
202
					ldap_get_option( lsc->ld,
Pierangelo Masarati's avatar
Pierangelo Masarati committed
203
204
205
206
207
						LDAP_OPT_ERROR_STRING, &err );

					if ( match != NULL ) {
						free( match );
					}
208
					ldap_get_option( lsc->ld,
Pierangelo Masarati's avatar
Pierangelo Masarati committed
209
210
211
212
213
						LDAP_OPT_MATCHED_DN, &match );
					
					last = i;
					break;
				}
214
				msgid[ i ] = -1;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
215
				--candidates;
216

Pierangelo Masarati's avatar
Pierangelo Masarati committed
217
			} else {
218
				msgid[ i ] = -1;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
219
220
221
222
223
224
225
226
227
				--candidates;
				if ( res ) {
					ldap_msgfree( res );
				}
				break;
			}
		}
	}

228
finish:;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250

	/*
	 * Rewrite the matched portion of the search base, if required
	 * 
	 * FIXME: only the last one gets caught!
	 */
	if ( count == 1 ) {
		if ( match != NULL ) {
			free( match );
			match = NULL;
		}
		
		/*
		 * the result of the compare is assigned to the res code
		 * that will be returned
		 */
		rres = cres;
		
		/*
		 * At least one compare failed with matched portion,
		 * and none was successful
		 */
251
252
253
254
255
256
	} else if ( match != NULL &&  match[0] != '\0' ) {
		struct berval matched;

		matched.bv_val = match;
		matched.bv_len = strlen( match );

257
		dc.ctx = "matchedDN";
258
		ldap_back_dn_massage( &dc, &matched, &mmatch );
259
260
	}

261
262
263
	if ( rres != LDAP_SUCCESS ) {
		rs->sr_err = rres;
	}
264
	rs->sr_matched = mmatch.bv_val;
265
266
	send_ldap_result( op, rs );
	rs->sr_matched = NULL;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
267
268

	if ( match != NULL ) {
269
270
		if ( mmatch.bv_val != match ) {
			free( mmatch.bv_val );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
271
272
273
274
275
276
277
278
279
280
281
		}
		free( match );
	}

	if ( msgid ) {
		free( msgid );
	}
	
	return rc;
}