1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 *
3 * The contents of this file are subject to the Netscape Public License
4 * Version 1.0 (the "NPL"); you may not use this file except in
5 * compliance with the NPL. You may obtain a copy of the NPL at
6 * http://www.mozilla.org/NPL/
7 *
8 * Software distributed under the NPL is distributed on an "AS IS" basis,
9 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
10 * for the specific language governing rights and limitations under the
11 * NPL.
12 *
13 * The Initial Developer of this code under the NPL is Netscape
14 * Communications Corporation. Portions created by Netscape are
15 * Copyright (C) 1998 Netscape Communications Corporation. All Rights
16 * Reserved.
17 */
18 /* control.c - routines to handle ldapv3 controls */
19
20 #include "ldap-int.h"
21
22 static LDAPControl *ldap_control_dup( LDAPControl *ctrl );
23 static int ldap_control_copy_contents( LDAPControl *ctrl_dst,
24 LDAPControl *ctrl_src );
25
26 /*
27 * Append a list of LDAPv3 controls to ber. If ctrls is NULL, use default
28 * set of controls from ld.
29 * Return an LDAP error code (LDAP_SUCCESS if all goes well).
30 * If closeseq is non-zero, we do an extra ber_put_seq() as well.
31 */
32 int
nsldapi_put_controls(LDAP * ld,LDAPControl ** ctrls,int closeseq,BerElement * ber)33 nsldapi_put_controls( LDAP *ld, LDAPControl **ctrls, int closeseq,
34 BerElement *ber )
35 {
36 LDAPControl *c;
37 int rc, i;
38
39 rc = LDAP_ENCODING_ERROR; /* the most popular error */
40
41 /* if no controls were passed in, use global list from LDAP * */
42 LDAP_MUTEX_LOCK( ld, LDAP_CTRL_LOCK );
43 if ( ctrls == NULL ) {
44 ctrls = ld->ld_servercontrols;
45 }
46
47 /* if there are no controls then we are done */
48 if ( ctrls == NULL || ctrls[ 0 ] == NULL ) {
49 goto clean_exit;
50 }
51
52 /*
53 * If we're using LDAPv2 or earlier we can't send any controls, so
54 * we just ignore them unless one is marked critical, in which case
55 * we return an error.
56 */
57 if ( NSLDAPI_LDAP_VERSION( ld ) < LDAP_VERSION3 ) {
58 for ( i = 0; ctrls != NULL && ctrls[i] != NULL; i++ ) {
59 if ( ctrls[i]->ldctl_iscritical ) {
60 rc = LDAP_NOT_SUPPORTED;
61 goto error_exit;
62 }
63 }
64 goto clean_exit;
65 }
66
67 /*
68 * encode the controls as a Sequence of Sequence
69 */
70 if ( ber_printf( ber, "t{", LDAP_TAG_CONTROLS ) == -1 ) {
71 goto error_exit;
72 }
73
74 for ( i = 0; ctrls[i] != NULL; i++ ) {
75 c = ctrls[i];
76
77 if ( ber_printf( ber, "{s", c->ldctl_oid ) == -1 ) {
78 goto error_exit;
79 }
80
81 /* criticality is "BOOLEAN DEFAULT FALSE" */
82 /* therefore, it should only be encoded if it exists AND is TRUE */
83 if ( c->ldctl_iscritical ) {
84 if ( ber_printf( ber, "b", (int)c->ldctl_iscritical )
85 == -1 ) {
86 goto error_exit;
87 }
88 }
89
90 if ( c->ldctl_value.bv_val != NULL ) {
91 if ( ber_printf( ber, "o", c->ldctl_value.bv_val,
92 (int)c->ldctl_value.bv_len /* XXX lossy cast */ )
93 == -1 ) {
94 goto error_exit;
95 }
96 }
97
98 if ( ber_put_seq( ber ) == -1 ) {
99 goto error_exit;
100 }
101 }
102
103 if ( ber_put_seq( ber ) == -1 ) {
104 goto error_exit;
105 }
106
107 clean_exit:
108 LDAP_MUTEX_UNLOCK( ld, LDAP_CTRL_LOCK );
109 if ( closeseq && ber_put_seq( ber ) == -1 ) {
110 goto error_exit;
111 }
112 return( LDAP_SUCCESS );
113
114 error_exit:
115 LDAP_MUTEX_UNLOCK( ld, LDAP_CTRL_LOCK );
116 LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
117 return( rc );
118 }
119
120
121 /*
122 * Pull controls out of "ber" (if any present) and return them in "controlsp."
123 * Returns an LDAP error code.
124 */
125 int
nsldapi_get_controls(BerElement * ber,LDAPControl *** controlsp)126 nsldapi_get_controls( BerElement *ber, LDAPControl ***controlsp )
127 {
128 LDAPControl *newctrl;
129 ber_tag_t tag;
130 ber_len_t len;
131 int rc, maxcontrols, curcontrols;
132 char *last;
133
134 /*
135 * Each LDAPMessage can have a set of controls appended
136 * to it. Controls are used to extend the functionality
137 * of an LDAP operation (e.g., add an attribute size limit
138 * to the search operation). These controls look like this:
139 *
140 * Controls ::= SEQUENCE OF Control
141 *
142 * Control ::= SEQUENCE {
143 * controlType LDAPOID,
144 * criticality BOOLEAN DEFAULT FALSE,
145 * controlValue OCTET STRING
146 * }
147 */
148 LDAPDebug( LDAP_DEBUG_TRACE, "=> nsldapi_get_controls\n", 0, 0, 0 );
149
150 *controlsp = NULL;
151
152 /*
153 * check to see if controls were included
154 */
155 if ( ber_get_option( ber, LBER_OPT_REMAINING_BYTES, &len ) != 0 ) {
156 return( LDAP_DECODING_ERROR ); /* unexpected error */
157 }
158 if ( len == 0 ) {
159 LDAPDebug( LDAP_DEBUG_TRACE,
160 "<= nsldapi_get_controls no controls\n", 0, 0, 0 );
161 return( LDAP_SUCCESS ); /* no controls */
162 }
163 if (( tag = ber_peek_tag( ber, &len )) != LDAP_TAG_CONTROLS ) {
164 if ( tag == LBER_ERROR ) {
165 LDAPDebug( LDAP_DEBUG_TRACE,
166 "<= nsldapi_get_controls LDAP_PROTOCOL_ERROR\n",
167 0, 0, 0 );
168 return( LDAP_DECODING_ERROR ); /* decoding error */
169 }
170 /*
171 * We found something other than controls. This should never
172 * happen in LDAPv3, but we don't treat this is a hard error --
173 * we just ignore the extra stuff.
174 */
175 LDAPDebug( LDAP_DEBUG_TRACE,
176 "<= nsldapi_get_controls ignoring unrecognized data in message (tag 0x%x)\n",
177 tag, 0, 0 );
178 return( LDAP_SUCCESS );
179 }
180
181 maxcontrols = curcontrols = 0;
182 for ( tag = ber_first_element( ber, &len, &last );
183 tag != LBER_ERROR && tag != LBER_END_OF_SEQORSET;
184 tag = ber_next_element( ber, &len, last ) ) {
185 if ( curcontrols >= maxcontrols - 1 ) {
186 #define CONTROL_GRABSIZE 5
187 maxcontrols += CONTROL_GRABSIZE;
188 *controlsp = (struct ldapcontrol **)NSLDAPI_REALLOC(
189 (char *)*controlsp, maxcontrols *
190 sizeof(struct ldapcontrol *) );
191 if ( *controlsp == NULL ) {
192 rc = LDAP_NO_MEMORY;
193 goto free_and_return;
194 }
195 }
196 if (( newctrl = (struct ldapcontrol *)NSLDAPI_CALLOC( 1,
197 sizeof(LDAPControl))) == NULL ) {
198 rc = LDAP_NO_MEMORY;
199 goto free_and_return;
200 }
201
202 (*controlsp)[curcontrols++] = newctrl;
203 (*controlsp)[curcontrols] = NULL;
204
205 if ( ber_scanf( ber, "{a", &newctrl->ldctl_oid )
206 == LBER_ERROR ) {
207 rc = LDAP_DECODING_ERROR;
208 goto free_and_return;
209 }
210
211 /* the criticality is optional */
212 if ( ber_peek_tag( ber, &len ) == LBER_BOOLEAN ) {
213 int aint;
214
215 if ( ber_scanf( ber, "b", &aint ) == LBER_ERROR ) {
216 rc = LDAP_DECODING_ERROR;
217 goto free_and_return;
218 }
219 newctrl->ldctl_iscritical = (char)aint; /* XXX lossy cast */
220 } else {
221 /* absent is synonomous with FALSE */
222 newctrl->ldctl_iscritical = 0;
223 }
224
225 /* the control value is optional */
226 if ( ber_peek_tag( ber, &len ) == LBER_OCTETSTRING ) {
227 if ( ber_scanf( ber, "o", &newctrl->ldctl_value )
228 == LBER_ERROR ) {
229 rc = LDAP_DECODING_ERROR;
230 goto free_and_return;
231 }
232 } else {
233 (newctrl->ldctl_value).bv_val = NULL;
234 (newctrl->ldctl_value).bv_len = 0;
235 }
236
237 }
238
239 if ( tag == LBER_ERROR ) {
240 rc = LDAP_DECODING_ERROR;
241 goto free_and_return;
242 }
243
244 LDAPDebug( LDAP_DEBUG_TRACE,
245 "<= nsldapi_get_controls found %d controls\n", curcontrols, 0, 0 );
246 return( LDAP_SUCCESS );
247
248 free_and_return:;
249 ldap_controls_free( *controlsp );
250 *controlsp = NULL;
251 LDAPDebug( LDAP_DEBUG_TRACE,
252 "<= nsldapi_get_controls error 0x%x\n", rc, 0, 0 );
253 return( rc );
254 }
255
256
257 void
258 LDAP_CALL
ldap_control_free(LDAPControl * ctrl)259 ldap_control_free( LDAPControl *ctrl )
260 {
261 if ( ctrl != NULL ) {
262 if ( ctrl->ldctl_oid != NULL ) {
263 NSLDAPI_FREE( ctrl->ldctl_oid );
264 }
265 if ( ctrl->ldctl_value.bv_val != NULL ) {
266 NSLDAPI_FREE( ctrl->ldctl_value.bv_val );
267 }
268 NSLDAPI_FREE( (char *)ctrl );
269 }
270 }
271
272
273 void
274 LDAP_CALL
ldap_controls_free(LDAPControl ** ctrls)275 ldap_controls_free( LDAPControl **ctrls )
276 {
277 int i;
278
279 if ( ctrls != NULL ) {
280 for ( i = 0; ctrls[i] != NULL; i++ ) {
281 ldap_control_free( ctrls[i] );
282 }
283 NSLDAPI_FREE( (char *)ctrls );
284 }
285 }
286
287
288
289 #if 0
290 LDAPControl **
291 LDAP_CALL
292 ldap_control_append( LDAPControl **ctrl_src, LDAPControl *ctrl )
293 {
294 int nctrls = 0;
295 LDAPControl **ctrlp;
296 int i;
297
298 if ( NULL == ctrl )
299 return ( NULL );
300
301 /* Count the existing controls */
302 if ( NULL != ctrl_src ) {
303 while( NULL != ctrl_src[nctrls] ) {
304 nctrls++;
305 }
306 }
307
308 /* allocate the new control structure */
309 if ( ( ctrlp = (LDAPControl **)NSLDAPI_MALLOC( sizeof(LDAPControl *)
310 * (nctrls + 2) ) ) == NULL ) {
311 return( NULL );
312 }
313 memset( ctrlp, 0, sizeof(*ctrlp) * (nctrls + 2) );
314
315 for( i = 0; i < (nctrls + 1); i++ ) {
316 if ( i < nctrls ) {
317 ctrlp[i] = ldap_control_dup( ctrl_src[i] );
318 } else {
319 ctrlp[i] = ldap_control_dup( ctrl );
320 }
321 if ( NULL == ctrlp[i] ) {
322 ldap_controls_free( ctrlp );
323 return( NULL );
324 }
325 }
326 return ctrlp;
327 }
328 #endif /* 0 */
329
330
331 /*
332 * Replace *ldctrls with a copy of newctrls.
333 * returns 0 if successful.
334 * return -1 if not and set error code inside LDAP *ld.
335 */
336 int
nsldapi_dup_controls(LDAP * ld,LDAPControl *** ldctrls,LDAPControl ** newctrls)337 nsldapi_dup_controls( LDAP *ld, LDAPControl ***ldctrls, LDAPControl **newctrls )
338 {
339 int count;
340
341 if ( *ldctrls != NULL ) {
342 ldap_controls_free( *ldctrls );
343 }
344
345 if ( newctrls == NULL || newctrls[0] == NULL ) {
346 *ldctrls = NULL;
347 return( 0 );
348 }
349
350 for ( count = 0; newctrls[ count ] != NULL; ++count ) {
351 ;
352 }
353
354 if (( *ldctrls = (LDAPControl **)NSLDAPI_MALLOC(( count + 1 ) *
355 sizeof( LDAPControl *))) == NULL ) {
356 LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
357 return( -1 );
358 }
359 (*ldctrls)[ count ] = NULL;
360
361 for ( count = 0; newctrls[ count ] != NULL; ++count ) {
362 if (( (*ldctrls)[ count ] =
363 ldap_control_dup( newctrls[ count ] )) == NULL ) {
364 ldap_controls_free( *ldctrls );
365 *ldctrls = NULL;
366 LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
367 return( -1 );
368 }
369 }
370
371 return( 0 );
372 }
373
374
375 /*
376 * return a malloc'd copy of "ctrl" (NULL if memory allocation fails)
377 */
378 static LDAPControl *
379 /* LDAP_CALL */ /* keep this routine internal for now */
ldap_control_dup(LDAPControl * ctrl)380 ldap_control_dup( LDAPControl *ctrl )
381 {
382 LDAPControl *rctrl;
383
384 if (( rctrl = (LDAPControl *)NSLDAPI_MALLOC( sizeof( LDAPControl )))
385 == NULL ) {
386 return( NULL );
387 }
388
389 if ( ldap_control_copy_contents( rctrl, ctrl ) != LDAP_SUCCESS ) {
390 NSLDAPI_FREE( rctrl );
391 return( NULL );
392 }
393
394 return( rctrl );
395 }
396
397
398 /*
399 * duplicate the contents of "ctrl_src" and place in "ctrl_dst"
400 */
401 static int
402 /* LDAP_CALL */ /* keep this routine internal for now */
ldap_control_copy_contents(LDAPControl * ctrl_dst,LDAPControl * ctrl_src)403 ldap_control_copy_contents( LDAPControl *ctrl_dst, LDAPControl *ctrl_src )
404 {
405 size_t len;
406
407 if ( NULL == ctrl_dst || NULL == ctrl_src ) {
408 return( LDAP_PARAM_ERROR );
409 }
410
411 ctrl_dst->ldctl_iscritical = ctrl_src->ldctl_iscritical;
412
413 /* fill in the fields of this new control */
414 if (( ctrl_dst->ldctl_oid = nsldapi_strdup( ctrl_src->ldctl_oid ))
415 == NULL ) {
416 return( LDAP_NO_MEMORY );
417 }
418
419 len = (size_t)(ctrl_src->ldctl_value).bv_len;
420 if ( ctrl_src->ldctl_value.bv_val == NULL || len <= 0 ) {
421 ctrl_dst->ldctl_value.bv_len = 0;
422 ctrl_dst->ldctl_value.bv_val = NULL;
423 } else {
424 ctrl_dst->ldctl_value.bv_len = len;
425 if (( ctrl_dst->ldctl_value.bv_val = NSLDAPI_MALLOC( len ))
426 == NULL ) {
427 NSLDAPI_FREE( ctrl_dst->ldctl_oid );
428 return( LDAP_NO_MEMORY );
429 }
430 SAFEMEMCPY( ctrl_dst->ldctl_value.bv_val,
431 ctrl_src->ldctl_value.bv_val, len );
432 }
433
434 return ( LDAP_SUCCESS );
435 }
436
437
438
439 /*
440 * build an allocated LDAPv3 control. Returns an LDAP error code.
441 */
442 int
nsldapi_build_control(char * oid,BerElement * ber,int freeber,char iscritical,LDAPControl ** ctrlp)443 nsldapi_build_control( char *oid, BerElement *ber, int freeber, char iscritical,
444 LDAPControl **ctrlp )
445 {
446 int rc;
447 struct berval *bvp;
448
449 if ( ber == NULL ) {
450 bvp = NULL;
451 } else {
452 /* allocate struct berval with contents of the BER encoding */
453 rc = ber_flatten( ber, &bvp );
454 if ( freeber ) {
455 ber_free( ber, 1 );
456 }
457 if ( rc == -1 ) {
458 return( LDAP_NO_MEMORY );
459 }
460 }
461
462 /* allocate the new control structure */
463 if (( *ctrlp = (LDAPControl *)NSLDAPI_MALLOC( sizeof(LDAPControl)))
464 == NULL ) {
465 if ( bvp != NULL ) {
466 ber_bvfree( bvp );
467 }
468 return( LDAP_NO_MEMORY );
469 }
470
471 /* fill in the fields of this new control */
472 (*ctrlp)->ldctl_iscritical = iscritical;
473 if (( (*ctrlp)->ldctl_oid = nsldapi_strdup( oid )) == NULL ) {
474 NSLDAPI_FREE( *ctrlp );
475 if ( bvp != NULL ) {
476 ber_bvfree( bvp );
477 }
478 return( LDAP_NO_MEMORY );
479 }
480
481 if ( bvp == NULL ) {
482 (*ctrlp)->ldctl_value.bv_len = 0;
483 (*ctrlp)->ldctl_value.bv_val = NULL;
484 } else {
485 (*ctrlp)->ldctl_value = *bvp; /* struct copy */
486 NSLDAPI_FREE( bvp ); /* free container, not contents! */
487 }
488
489 return( LDAP_SUCCESS );
490 }
491