1 /* $NetBSD: controls.c,v 1.3 2021/08/14 16:14:55 christos Exp $ */
2
3 /* $OpenLDAP$ */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 *
6 * Copyright 1998-2021 The OpenLDAP Foundation.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted only as authorized by the OpenLDAP
11 * Public License.
12 *
13 * A copy of this license is available in the file LICENSE in the
14 * top-level directory of the distribution or, alternatively, at
15 * <http://www.OpenLDAP.org/license.html>.
16 */
17 /* This notice applies to changes, created by or for Novell, Inc.,
18 * to preexisting works for which notices appear elsewhere in this file.
19 *
20 * Copyright (C) 1999, 2000 Novell, Inc. All Rights Reserved.
21 *
22 * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND TREATIES.
23 * USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT TO VERSION
24 * 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS AVAILABLE AT
25 * HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE" IN THE
26 * TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION OF THIS
27 * WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP PUBLIC
28 * LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT THE
29 * PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY.
30 *---
31 * Note: A verbatim copy of version 2.0.1 of the OpenLDAP Public License
32 * can be found in the file "build/LICENSE-2.0.1" in this distribution
33 * of OpenLDAP Software.
34 */
35
36 #include <sys/cdefs.h>
37 __RCSID("$NetBSD: controls.c,v 1.3 2021/08/14 16:14:55 christos Exp $");
38
39 #include "portable.h"
40
41 #include <ac/stdlib.h>
42
43 #include <ac/time.h>
44 #include <ac/string.h>
45
46 #include "ldap-int.h"
47
48 /* LDAPv3 Controls (RFC 4511)
49 *
50 * Controls ::= SEQUENCE OF control Control
51 *
52 * Control ::= SEQUENCE {
53 * controlType LDAPOID,
54 * criticality BOOLEAN DEFAULT FALSE,
55 * controlValue OCTET STRING OPTIONAL
56 * }
57 */
58
59 int
ldap_pvt_put_control(const LDAPControl * c,BerElement * ber)60 ldap_pvt_put_control(
61 const LDAPControl *c,
62 BerElement *ber )
63 {
64 if ( ber_printf( ber, "{s" /*}*/, c->ldctl_oid ) == -1 ) {
65 return LDAP_ENCODING_ERROR;
66 }
67
68 if ( c->ldctl_iscritical /* only if true */
69 && ( ber_printf( ber, "b",
70 (ber_int_t) c->ldctl_iscritical ) == -1 ) )
71 {
72 return LDAP_ENCODING_ERROR;
73 }
74
75 if ( !BER_BVISNULL( &c->ldctl_value ) /* only if we have a value */
76 && ( ber_printf( ber, "O", &c->ldctl_value ) == -1 ) )
77 {
78 return LDAP_ENCODING_ERROR;
79 }
80
81 if ( ber_printf( ber, /*{*/"N}" ) == -1 ) {
82 return LDAP_ENCODING_ERROR;
83 }
84
85 return LDAP_SUCCESS;
86 }
87
88
89 /*
90 * ldap_int_put_controls
91 */
92
93 int
ldap_int_put_controls(LDAP * ld,LDAPControl * const * ctrls,BerElement * ber)94 ldap_int_put_controls(
95 LDAP *ld,
96 LDAPControl *const *ctrls,
97 BerElement *ber )
98 {
99 LDAPControl *const *c;
100
101 assert( ld != NULL );
102 assert( LDAP_VALID( ld ) );
103 assert( ber != NULL );
104
105 if( ctrls == NULL ) {
106 /* use default server controls */
107 ctrls = ld->ld_sctrls;
108 }
109
110 if( ctrls == NULL || *ctrls == NULL ) {
111 return LDAP_SUCCESS;
112 }
113
114 if ( ld->ld_version < LDAP_VERSION3 ) {
115 /* LDAPv2 doesn't support controls,
116 * error if any control is critical
117 */
118 for( c = ctrls ; *c != NULL; c++ ) {
119 if( (*c)->ldctl_iscritical ) {
120 ld->ld_errno = LDAP_NOT_SUPPORTED;
121 return ld->ld_errno;
122 }
123 }
124
125 return LDAP_SUCCESS;
126 }
127
128 /* Controls are encoded as a sequence of sequences */
129 if( ber_printf( ber, "t{"/*}*/, LDAP_TAG_CONTROLS ) == -1 ) {
130 ld->ld_errno = LDAP_ENCODING_ERROR;
131 return ld->ld_errno;
132 }
133
134 for( c = ctrls ; *c != NULL; c++ ) {
135 ld->ld_errno = ldap_pvt_put_control( *c, ber );
136 if ( ld->ld_errno != LDAP_SUCCESS ) {
137 return ld->ld_errno;
138 }
139 }
140
141
142 if( ber_printf( ber, /*{*/ "}" ) == -1 ) {
143 ld->ld_errno = LDAP_ENCODING_ERROR;
144 return ld->ld_errno;
145 }
146
147 return LDAP_SUCCESS;
148 }
149
ldap_pvt_get_controls(BerElement * ber,LDAPControl *** ctrls)150 int ldap_pvt_get_controls(
151 BerElement *ber,
152 LDAPControl ***ctrls )
153 {
154 int nctrls;
155 ber_tag_t tag;
156 ber_len_t len;
157 char *opaque;
158
159 assert( ber != NULL );
160
161 if( ctrls == NULL ) {
162 return LDAP_SUCCESS;
163 }
164 *ctrls = NULL;
165
166 len = ber_pvt_ber_remaining( ber );
167
168 if( len == 0) {
169 /* no controls */
170 return LDAP_SUCCESS;
171 }
172
173 if(( tag = ber_peek_tag( ber, &len )) != LDAP_TAG_CONTROLS ) {
174 if( tag == LBER_ERROR ) {
175 /* decoding error */
176 return LDAP_DECODING_ERROR;
177 }
178
179 /* ignore unexpected input */
180 return LDAP_SUCCESS;
181 }
182
183 /* set through each element */
184 nctrls = 0;
185 *ctrls = LDAP_MALLOC( 1 * sizeof(LDAPControl *) );
186
187 if( *ctrls == NULL ) {
188 return LDAP_NO_MEMORY;
189 }
190
191 *ctrls[nctrls] = NULL;
192
193 for( tag = ber_first_element( ber, &len, &opaque );
194 tag != LBER_ERROR;
195 tag = ber_next_element( ber, &len, opaque ) )
196 {
197 LDAPControl *tctrl;
198 LDAPControl **tctrls;
199
200 tctrl = LDAP_CALLOC( 1, sizeof(LDAPControl) );
201
202 /* allocate pointer space for current controls (nctrls)
203 * + this control + extra NULL
204 */
205 tctrls = (tctrl == NULL) ? NULL :
206 LDAP_REALLOC(*ctrls, (nctrls+2) * sizeof(LDAPControl *));
207
208 if( tctrls == NULL ) {
209 /* one of the above allocation failed */
210
211 if( tctrl != NULL ) {
212 LDAP_FREE( tctrl );
213 }
214
215 ldap_controls_free(*ctrls);
216 *ctrls = NULL;
217
218 return LDAP_NO_MEMORY;
219 }
220
221
222 tctrls[nctrls++] = tctrl;
223 tctrls[nctrls] = NULL;
224
225 tag = ber_scanf( ber, "{a" /*}*/, &tctrl->ldctl_oid );
226
227 if( tag == LBER_ERROR ) {
228 *ctrls = NULL;
229 ldap_controls_free( tctrls );
230 return LDAP_DECODING_ERROR;
231 }
232
233 tag = ber_peek_tag( ber, &len );
234
235 if( tag == LBER_BOOLEAN ) {
236 ber_int_t crit;
237 tag = ber_scanf( ber, "b", &crit );
238 tctrl->ldctl_iscritical = crit ? (char) 0 : (char) ~0;
239 tag = ber_peek_tag( ber, &len );
240 }
241
242 if( tag == LBER_OCTETSTRING ) {
243 tag = ber_scanf( ber, "o", &tctrl->ldctl_value );
244 } else {
245 BER_BVZERO( &tctrl->ldctl_value );
246 }
247
248 *ctrls = tctrls;
249 }
250
251 return LDAP_SUCCESS;
252 }
253
254 /*
255 * Free a LDAPControl
256 */
257 void
ldap_control_free(LDAPControl * c)258 ldap_control_free( LDAPControl *c )
259 {
260 LDAP_MEMORY_DEBUG_ASSERT( c != NULL );
261
262 if ( c != NULL ) {
263 if( c->ldctl_oid != NULL) {
264 LDAP_FREE( c->ldctl_oid );
265 }
266
267 if( c->ldctl_value.bv_val != NULL ) {
268 LDAP_FREE( c->ldctl_value.bv_val );
269 }
270
271 LDAP_FREE( c );
272 }
273 }
274
275 /*
276 * Free an array of LDAPControl's
277 */
278 void
ldap_controls_free(LDAPControl ** controls)279 ldap_controls_free( LDAPControl **controls )
280 {
281 LDAP_MEMORY_DEBUG_ASSERT( controls != NULL );
282
283 if ( controls != NULL ) {
284 int i;
285
286 for( i=0; controls[i] != NULL; i++) {
287 ldap_control_free( controls[i] );
288 }
289
290 LDAP_FREE( controls );
291 }
292 }
293
294 /*
295 * Duplicate an array of LDAPControl
296 */
297 LDAPControl **
ldap_controls_dup(LDAPControl * const * controls)298 ldap_controls_dup( LDAPControl *const *controls )
299 {
300 LDAPControl **new;
301 int i;
302
303 if ( controls == NULL ) {
304 return NULL;
305 }
306
307 /* count the controls */
308 for(i=0; controls[i] != NULL; i++) /* empty */ ;
309
310 if( i < 1 ) {
311 /* no controls to duplicate */
312 return NULL;
313 }
314
315 new = (LDAPControl **) LDAP_MALLOC( (i+1) * sizeof(LDAPControl *) );
316
317 if( new == NULL ) {
318 /* memory allocation failure */
319 return NULL;
320 }
321
322 /* duplicate the controls */
323 for(i=0; controls[i] != NULL; i++) {
324 new[i] = ldap_control_dup( controls[i] );
325
326 if( new[i] == NULL ) {
327 ldap_controls_free( new );
328 return NULL;
329 }
330 }
331
332 new[i] = NULL;
333
334 return new;
335 }
336
337 /*
338 * Duplicate a LDAPControl
339 */
340 LDAPControl *
ldap_control_dup(const LDAPControl * c)341 ldap_control_dup( const LDAPControl *c )
342 {
343 LDAPControl *new;
344
345 if ( c == NULL || c->ldctl_oid == NULL ) {
346 return NULL;
347 }
348
349 new = (LDAPControl *) LDAP_MALLOC( sizeof(LDAPControl) );
350
351 if( new == NULL ) {
352 return NULL;
353 }
354
355 new->ldctl_oid = LDAP_STRDUP( c->ldctl_oid );
356
357 if(new->ldctl_oid == NULL) {
358 LDAP_FREE( new );
359 return NULL;
360 }
361
362 if( c->ldctl_value.bv_val != NULL ) {
363 new->ldctl_value.bv_val =
364 (char *) LDAP_MALLOC( c->ldctl_value.bv_len + 1 );
365
366 if(new->ldctl_value.bv_val == NULL) {
367 if(new->ldctl_oid != NULL) {
368 LDAP_FREE( new->ldctl_oid );
369 }
370 LDAP_FREE( new );
371 return NULL;
372 }
373
374 new->ldctl_value.bv_len = c->ldctl_value.bv_len;
375
376 AC_MEMCPY( new->ldctl_value.bv_val, c->ldctl_value.bv_val,
377 c->ldctl_value.bv_len );
378
379 new->ldctl_value.bv_val[new->ldctl_value.bv_len] = '\0';
380
381 } else {
382 new->ldctl_value.bv_len = 0;
383 new->ldctl_value.bv_val = NULL;
384 }
385
386 new->ldctl_iscritical = c->ldctl_iscritical;
387 return new;
388 }
389
390 /*
391 * Find a LDAPControl - deprecated
392 */
393 LDAPControl *
ldap_find_control(LDAP_CONST char * oid,LDAPControl ** ctrls)394 ldap_find_control(
395 LDAP_CONST char *oid,
396 LDAPControl **ctrls )
397 {
398 if( ctrls == NULL || *ctrls == NULL ) {
399 return NULL;
400 }
401
402 for( ; *ctrls != NULL; ctrls++ ) {
403 if( strcmp( (*ctrls)->ldctl_oid, oid ) == 0 ) {
404 return *ctrls;
405 }
406 }
407
408 return NULL;
409 }
410
411 /*
412 * Find a LDAPControl
413 */
414 LDAPControl *
ldap_control_find(LDAP_CONST char * oid,LDAPControl ** ctrls,LDAPControl *** nextctrlp)415 ldap_control_find(
416 LDAP_CONST char *oid,
417 LDAPControl **ctrls,
418 LDAPControl ***nextctrlp )
419 {
420 if ( oid == NULL || ctrls == NULL || *ctrls == NULL ) {
421 return NULL;
422 }
423
424 for( ; *ctrls != NULL; ctrls++ ) {
425 if( strcmp( (*ctrls)->ldctl_oid, oid ) == 0 ) {
426 if ( nextctrlp != NULL ) {
427 *nextctrlp = ctrls + 1;
428 }
429
430 return *ctrls;
431 }
432 }
433
434 if ( nextctrlp != NULL ) {
435 *nextctrlp = NULL;
436 }
437
438 return NULL;
439 }
440
441 /*
442 * Create a LDAPControl, optionally from ber - deprecated
443 */
444 int
ldap_create_control(LDAP_CONST char * requestOID,BerElement * ber,int iscritical,LDAPControl ** ctrlp)445 ldap_create_control(
446 LDAP_CONST char *requestOID,
447 BerElement *ber,
448 int iscritical,
449 LDAPControl **ctrlp )
450 {
451 LDAPControl *ctrl;
452
453 assert( requestOID != NULL );
454 assert( ctrlp != NULL );
455
456 ctrl = (LDAPControl *) LDAP_MALLOC( sizeof(LDAPControl) );
457 if ( ctrl == NULL ) {
458 return LDAP_NO_MEMORY;
459 }
460
461 BER_BVZERO(&ctrl->ldctl_value);
462 if ( ber && ( ber_flatten2( ber, &ctrl->ldctl_value, 1 ) == -1 )) {
463 LDAP_FREE( ctrl );
464 return LDAP_NO_MEMORY;
465 }
466
467 ctrl->ldctl_oid = LDAP_STRDUP( requestOID );
468 ctrl->ldctl_iscritical = iscritical;
469
470 if ( requestOID != NULL && ctrl->ldctl_oid == NULL ) {
471 ldap_control_free( ctrl );
472 return LDAP_NO_MEMORY;
473 }
474
475 *ctrlp = ctrl;
476 return LDAP_SUCCESS;
477 }
478
479 /*
480 * Create a LDAPControl, optionally from value
481 */
482 int
ldap_control_create(LDAP_CONST char * requestOID,int iscritical,struct berval * value,int dupval,LDAPControl ** ctrlp)483 ldap_control_create(
484 LDAP_CONST char *requestOID,
485 int iscritical,
486 struct berval *value,
487 int dupval,
488 LDAPControl **ctrlp )
489 {
490 LDAPControl *ctrl;
491
492 assert( requestOID != NULL );
493 assert( ctrlp != NULL );
494
495 ctrl = (LDAPControl *) LDAP_CALLOC( sizeof(LDAPControl), 1 );
496 if ( ctrl == NULL ) {
497 return LDAP_NO_MEMORY;
498 }
499
500 ctrl->ldctl_iscritical = iscritical;
501 if ( requestOID != NULL ) {
502 ctrl->ldctl_oid = LDAP_STRDUP( requestOID );
503 if ( ctrl->ldctl_oid == NULL ) {
504 ldap_control_free( ctrl );
505 return LDAP_NO_MEMORY;
506 }
507 }
508
509 if ( value && !BER_BVISNULL( value ) ) {
510 if ( dupval ) {
511 ber_dupbv( &ctrl->ldctl_value, value );
512 if ( BER_BVISNULL( &ctrl->ldctl_value ) ) {
513 ldap_control_free( ctrl );
514 return LDAP_NO_MEMORY;
515 }
516
517 } else {
518 ctrl->ldctl_value = *value;
519 }
520 }
521
522 *ctrlp = ctrl;
523
524 return LDAP_SUCCESS;
525 }
526
527 /*
528 * check for critical client controls and bitch if present
529 * if we ever support critical controls, we'll have to
530 * find a means for maintaining per API call control
531 * information.
532 */
ldap_int_client_controls(LDAP * ld,LDAPControl ** ctrls)533 int ldap_int_client_controls( LDAP *ld, LDAPControl **ctrls )
534 {
535 LDAPControl *const *c;
536
537 assert( ld != NULL );
538 assert( LDAP_VALID( ld ) );
539
540 if( ctrls == NULL ) {
541 /* use default client controls */
542 ctrls = ld->ld_cctrls;
543 }
544
545 if( ctrls == NULL || *ctrls == NULL ) {
546 return LDAP_SUCCESS;
547 }
548
549 for( c = ctrls ; *c != NULL; c++ ) {
550 if( (*c)->ldctl_iscritical ) {
551 ld->ld_errno = LDAP_NOT_SUPPORTED;
552 return ld->ld_errno;
553 }
554 }
555
556 return LDAP_SUCCESS;
557 }
558