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