1/*	$NetBSD: slapi_dn.c,v 1.3 2021/08/14 16:15:02 christos Exp $	*/
2
3/* $OpenLDAP$ */
4/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 *
6 * Copyright 2005-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/* ACKNOWLEDGEMENTS:
18 * This work was initially developed by Luke Howard for inclusion
19 * in OpenLDAP Software.
20 */
21
22#include <sys/cdefs.h>
23__RCSID("$NetBSD: slapi_dn.c,v 1.3 2021/08/14 16:15:02 christos Exp $");
24
25#include "portable.h"
26
27#include <ac/string.h>
28#include <ac/stdarg.h>
29#include <ac/ctype.h>
30#include <ac/unistd.h>
31#include <ldap_pvt.h>
32
33#include <slap.h>
34#include <slapi.h>
35
36#ifdef LDAP_SLAPI
37#define FLAG_DN 0x1
38#define FLAG_NDN 0x2
39
40void slapi_sdn_init( Slapi_DN *sdn )
41{
42	sdn->flag = 0;
43	BER_BVZERO( &sdn->dn );
44	BER_BVZERO( &sdn->ndn );
45}
46
47Slapi_DN *slapi_sdn_new( void )
48{
49	Slapi_DN *sdn;
50
51	sdn = (Slapi_DN *)slapi_ch_malloc( sizeof(*sdn ));
52	slapi_sdn_init( sdn );
53
54	return sdn;
55}
56
57void slapi_sdn_done( Slapi_DN *sdn )
58{
59	if ( sdn == NULL )
60		return;
61
62	if ( sdn->flag & FLAG_DN ) {
63		slapi_ch_free_string( &sdn->dn.bv_val );
64	}
65	if ( sdn->flag & FLAG_NDN ) {
66		slapi_ch_free_string( &sdn->ndn.bv_val );
67	}
68
69	slapi_sdn_init( sdn );
70}
71
72void slapi_sdn_free( Slapi_DN **sdn )
73{
74	slapi_sdn_done( *sdn );
75	slapi_ch_free( (void **)sdn );
76}
77
78const char *slapi_sdn_get_dn( const Slapi_DN *sdn )
79{
80	if ( !BER_BVISNULL( &sdn->dn ) )
81		return sdn->dn.bv_val;
82	else
83		return sdn->ndn.bv_val;
84}
85
86const char *slapi_sdn_get_ndn( const Slapi_DN *sdn )
87{
88	if ( BER_BVISNULL( &sdn->ndn ) ) {
89		dnNormalize( 0, NULL, NULL,
90			(struct berval *)&sdn->dn, (struct berval *)&sdn->ndn, NULL );
91		((Slapi_DN *)sdn)->flag |= FLAG_NDN;
92	}
93
94	return sdn->ndn.bv_val;
95}
96
97Slapi_DN *slapi_sdn_new_dn_byval( const char *dn )
98{
99	Slapi_DN *sdn;
100
101	sdn = slapi_sdn_new();
102	return slapi_sdn_set_dn_byval( sdn, dn );
103}
104
105Slapi_DN *slapi_sdn_new_ndn_byval( const char *ndn )
106{
107	Slapi_DN *sdn;
108
109	sdn = slapi_sdn_new();
110	return slapi_sdn_set_ndn_byval( sdn, ndn );
111}
112
113Slapi_DN *slapi_sdn_new_dn_byref( const char *dn )
114{
115	Slapi_DN *sdn;
116
117	sdn = slapi_sdn_new();
118	return slapi_sdn_set_dn_byref( sdn, dn );
119}
120
121Slapi_DN *slapi_sdn_new_ndn_byref( const char *ndn )
122{
123	Slapi_DN *sdn;
124
125	sdn = slapi_sdn_new();
126	return slapi_sdn_set_ndn_byref( sdn, ndn );
127}
128
129Slapi_DN *slapi_sdn_new_dn_passin( const char *dn )
130{
131	Slapi_DN *sdn;
132
133	sdn = slapi_sdn_new();
134	return slapi_sdn_set_dn_passin( sdn, dn );
135}
136
137Slapi_DN *slapi_sdn_set_dn_byval( Slapi_DN *sdn, const char *dn )
138{
139	if ( sdn == NULL ) {
140		return NULL;
141	}
142
143	slapi_sdn_done( sdn );
144	if ( dn != NULL ) {
145		sdn->dn.bv_val = slapi_ch_strdup( dn );
146		sdn->dn.bv_len = strlen( dn );
147	}
148	sdn->flag |= FLAG_DN;
149
150	return sdn;
151}
152
153Slapi_DN *slapi_sdn_set_dn_byref( Slapi_DN *sdn, const char *dn )
154{
155	if ( sdn == NULL )
156		return NULL;
157
158	slapi_sdn_done( sdn );
159	if ( dn != NULL ) {
160		sdn->dn.bv_val = (char *)dn;
161		sdn->dn.bv_len = strlen( dn );
162	}
163
164	return sdn;
165}
166
167Slapi_DN *slapi_sdn_set_dn_passin( Slapi_DN *sdn, const char *dn )
168{
169	if ( sdn == NULL )
170		return NULL;
171
172	slapi_sdn_set_dn_byref( sdn, dn );
173	sdn->flag |= FLAG_DN;
174
175	return sdn;
176}
177
178Slapi_DN *slapi_sdn_set_ndn_byval( Slapi_DN *sdn, const char *ndn )
179{
180	if ( sdn == NULL ) {
181		return NULL;
182	}
183
184	slapi_sdn_done( sdn );
185	if ( ndn != NULL ) {
186		sdn->ndn.bv_val = slapi_ch_strdup( ndn );
187		sdn->ndn.bv_len = strlen( ndn );
188	}
189	sdn->flag |= FLAG_NDN;
190
191	return sdn;
192}
193
194Slapi_DN *slapi_sdn_set_ndn_byref( Slapi_DN *sdn, const char *ndn )
195{
196	if ( sdn == NULL )
197		return NULL;
198
199	slapi_sdn_done( sdn );
200	if ( ndn != NULL ) {
201		sdn->ndn.bv_val = (char *)ndn;
202		sdn->ndn.bv_len = strlen( ndn );
203	}
204
205	return sdn;
206}
207
208Slapi_DN *slapi_sdn_set_ndn_passin( Slapi_DN *sdn, const char *ndn )
209{
210	if ( sdn == NULL )
211		return NULL;
212
213	slapi_sdn_set_ndn_byref( sdn, ndn );
214	sdn->flag |= FLAG_NDN;
215
216	return sdn;
217}
218
219void slapi_sdn_get_parent( const Slapi_DN *sdn, Slapi_DN *sdn_parent )
220{
221	struct berval parent_dn;
222
223	if ( !(sdn->flag & FLAG_DN) ) {
224		dnParent( (struct berval *)&sdn->ndn, &parent_dn );
225		slapi_sdn_set_ndn_byval( sdn_parent, parent_dn.bv_val );
226	} else {
227		dnParent( (struct berval *)&sdn->dn, &parent_dn );
228		slapi_sdn_set_dn_byval( sdn_parent, parent_dn.bv_val );
229	}
230}
231
232void slapi_sdn_get_backend_parent( const Slapi_DN *sdn,
233	Slapi_DN *sdn_parent,
234	const Slapi_Backend *backend )
235{
236	slapi_sdn_get_ndn( sdn );
237
238	if ( backend == NULL ||
239	     be_issuffix( (Slapi_Backend *)backend, (struct berval *)&sdn->ndn ) == 0 ) {
240		slapi_sdn_get_parent( sdn, sdn_parent );
241	}
242
243}
244
245Slapi_DN * slapi_sdn_dup( const Slapi_DN *sdn )
246{
247	Slapi_DN *new_sdn;
248
249	new_sdn = slapi_sdn_new();
250	slapi_sdn_copy( sdn, new_sdn );
251
252	return new_sdn;
253}
254
255void slapi_sdn_copy( const Slapi_DN *from, Slapi_DN *to )
256{
257	slapi_sdn_set_dn_byval( to, from->dn.bv_val );
258}
259
260int slapi_sdn_compare( const Slapi_DN *sdn1, const Slapi_DN *sdn2 )
261{
262	int match = -1;
263
264	slapi_sdn_get_ndn( sdn1 );
265	slapi_sdn_get_ndn( sdn2 );
266
267	dnMatch( &match, 0, slap_schema.si_syn_distinguishedName, NULL,
268		(struct berval *)&sdn1->ndn, (void *)&sdn2->ndn );
269
270	return match;
271}
272
273int slapi_sdn_isempty( const Slapi_DN *sdn)
274{
275	return ( BER_BVISEMPTY( &sdn->dn ) && BER_BVISEMPTY( &sdn->ndn ) );
276}
277
278int slapi_sdn_issuffix( const Slapi_DN *sdn, const Slapi_DN *suffix_sdn )
279{
280	slapi_sdn_get_ndn( sdn );
281	slapi_sdn_get_ndn( suffix_sdn );
282
283	return dnIsSuffix( &sdn->ndn, &suffix_sdn->ndn );
284}
285
286int slapi_sdn_isparent( const Slapi_DN *parent, const Slapi_DN *child )
287{
288	Slapi_DN child_parent;
289
290	slapi_sdn_get_ndn( child );
291
292	slapi_sdn_init( &child_parent );
293	dnParent( (struct berval *)&child->ndn, &child_parent.ndn );
294
295	return ( slapi_sdn_compare( parent, &child_parent ) == 0 );
296}
297
298int slapi_sdn_isgrandparent( const Slapi_DN *parent, const Slapi_DN *child )
299{
300	Slapi_DN child_grandparent;
301
302	slapi_sdn_get_ndn( child );
303
304	slapi_sdn_init( &child_grandparent );
305	dnParent( (struct berval *)&child->ndn, &child_grandparent.ndn );
306	if ( child_grandparent.ndn.bv_len == 0 ) {
307		return 0;
308	}
309
310	dnParent( &child_grandparent.ndn, &child_grandparent.ndn );
311
312	return ( slapi_sdn_compare( parent, &child_grandparent ) == 0 );
313}
314
315int slapi_sdn_get_ndn_len( const Slapi_DN *sdn )
316{
317	slapi_sdn_get_ndn( sdn );
318
319	return sdn->ndn.bv_len;
320}
321
322int slapi_sdn_scope_test( const Slapi_DN *dn, const Slapi_DN *base, int scope )
323{
324	int rc;
325
326	switch ( scope ) {
327	case LDAP_SCOPE_BASE:
328		rc = ( slapi_sdn_compare( dn, base ) == 0 );
329		break;
330	case LDAP_SCOPE_ONELEVEL:
331		rc = slapi_sdn_isparent( base, dn );
332		break;
333	case LDAP_SCOPE_SUBTREE:
334		rc = slapi_sdn_issuffix( dn, base );
335		break;
336	default:
337		rc = 0;
338		break;
339	}
340
341	return rc;
342}
343
344void slapi_rdn_init( Slapi_RDN *rdn )
345{
346	rdn->flag = 0;
347	BER_BVZERO( &rdn->bv );
348	rdn->rdn = NULL;
349}
350
351Slapi_RDN *slapi_rdn_new( void )
352{
353	Slapi_RDN *rdn;
354
355	rdn = (Slapi_RDN *)slapi_ch_malloc( sizeof(*rdn ));
356	slapi_rdn_init( rdn );
357
358	return rdn;
359}
360
361Slapi_RDN *slapi_rdn_new_dn( const char *dn )
362{
363	Slapi_RDN *rdn;
364
365	rdn = slapi_rdn_new();
366	slapi_rdn_init_dn( rdn, dn );
367	return rdn;
368}
369
370Slapi_RDN *slapi_rdn_new_sdn( const Slapi_DN *sdn )
371{
372	return slapi_rdn_new_dn( slapi_sdn_get_dn( sdn ) );
373}
374
375Slapi_RDN *slapi_rdn_new_rdn( const Slapi_RDN *fromrdn )
376{
377	return slapi_rdn_new_dn( fromrdn->bv.bv_val );
378}
379
380void slapi_rdn_init_dn( Slapi_RDN *rdn, const char *dn )
381{
382	slapi_rdn_init( rdn );
383	slapi_rdn_set_dn( rdn, dn );
384}
385
386void slapi_rdn_init_sdn( Slapi_RDN *rdn, const Slapi_DN *sdn )
387{
388	slapi_rdn_init( rdn );
389	slapi_rdn_set_sdn( rdn, sdn );
390}
391
392void slapi_rdn_init_rdn( Slapi_RDN *rdn, const Slapi_RDN *fromrdn )
393{
394	slapi_rdn_init( rdn );
395	slapi_rdn_set_rdn( rdn, fromrdn );
396}
397
398void slapi_rdn_set_dn( Slapi_RDN *rdn, const char *dn )
399{
400	struct berval bv;
401
402	slapi_rdn_done( rdn );
403
404	BER_BVZERO( &bv );
405
406	if ( dn != NULL ) {
407		bv.bv_val = (char *)dn;
408		bv.bv_len = strlen( dn );
409	}
410
411	dnExtractRdn( &bv, &rdn->bv, NULL );
412	rdn->flag |= FLAG_DN;
413}
414
415void slapi_rdn_set_sdn( Slapi_RDN *rdn, const Slapi_DN *sdn )
416{
417	slapi_rdn_set_dn( rdn, slapi_sdn_get_dn( sdn ) );
418}
419
420void slapi_rdn_set_rdn( Slapi_RDN *rdn, const Slapi_RDN *fromrdn )
421{
422	slapi_rdn_set_dn( rdn, fromrdn->bv.bv_val );
423}
424
425void slapi_rdn_free( Slapi_RDN **rdn )
426{
427	slapi_rdn_done( *rdn );
428	slapi_ch_free( (void **)rdn );
429}
430
431void slapi_rdn_done( Slapi_RDN *rdn )
432{
433	if ( rdn->rdn != NULL ) {
434		ldap_rdnfree( rdn->rdn );
435		rdn->rdn = NULL;
436	}
437	slapi_ch_free_string( &rdn->bv.bv_val );
438	slapi_rdn_init( rdn );
439}
440
441const char *slapi_rdn_get_rdn( const Slapi_RDN *rdn )
442{
443	return rdn->bv.bv_val;
444}
445
446static int slapi_int_rdn_explode( Slapi_RDN *rdn )
447{
448	char *next;
449
450	if ( rdn->rdn != NULL ) {
451		return LDAP_SUCCESS;
452	}
453
454	return ldap_bv2rdn( &rdn->bv, &rdn->rdn, &next, LDAP_DN_FORMAT_LDAP );
455}
456
457static int slapi_int_rdn_implode( Slapi_RDN *rdn )
458{
459	struct berval bv;
460	int rc;
461
462	if ( rdn->rdn == NULL ) {
463		return LDAP_SUCCESS;
464	}
465
466	rc = ldap_rdn2bv( rdn->rdn, &bv, LDAP_DN_FORMAT_LDAPV3 | LDAP_DN_PRETTY );
467	if ( rc != LDAP_SUCCESS ) {
468		return rc;
469	}
470
471	slapi_ch_free_string( &rdn->bv.bv_val );
472	rdn->bv = bv;
473
474	return 0;
475}
476
477int slapi_rdn_get_num_components( Slapi_RDN *rdn )
478{
479	int i;
480
481	if ( slapi_int_rdn_explode( rdn ) != LDAP_SUCCESS )
482		return 0;
483
484	for ( i = 0; rdn->rdn[i] != NULL; i++ )
485		;
486
487	return i;
488}
489
490int slapi_rdn_get_first( Slapi_RDN *rdn, char **type, char **value )
491{
492	return slapi_rdn_get_next( rdn, 0, type, value );
493}
494
495int slapi_rdn_get_next( Slapi_RDN *rdn, int index, char **type, char **value )
496{
497	slapi_int_rdn_explode( rdn );
498
499	if ( rdn->rdn == NULL || rdn->rdn[index] == NULL )
500		return -1;
501
502	*type = rdn->rdn[index]->la_attr.bv_val;
503	*value = rdn->rdn[index]->la_value.bv_val;
504
505	return index + 1;
506}
507
508int slapi_rdn_get_index( Slapi_RDN *rdn, const char *type, const char *value, size_t length )
509{
510	int i, match;
511	struct berval bv;
512	AttributeDescription *ad = NULL;
513	const char *text;
514
515	slapi_int_rdn_explode( rdn );
516
517	if ( slap_str2ad( type, &ad, &text ) != LDAP_SUCCESS ) {
518		return -1;
519	}
520
521	bv.bv_val = (char *)value;
522	bv.bv_len = length;
523
524	for ( i = 0; rdn->rdn[i] != NULL; i++ ) {
525		if ( !slapi_attr_types_equivalent( ad->ad_cname.bv_val, type ))
526			continue;
527
528		if ( value_match( &match, ad, ad->ad_type->sat_equality, 0,
529			&rdn->rdn[i]->la_value, (void *)&bv, &text ) != LDAP_SUCCESS )
530			match = -1;
531
532		if ( match == 0 )
533			return i;
534	}
535
536	return -1;
537}
538
539int slapi_rdn_get_index_attr( Slapi_RDN *rdn, const char *type, char **value )
540{
541	int i;
542
543	for ( i = 0; rdn->rdn[i] != NULL; i++ ) {
544		if ( slapi_attr_types_equivalent( rdn->rdn[i]->la_attr.bv_val, type ) ) {
545			*value = rdn->rdn[i]->la_value.bv_val;
546			return i;
547		}
548	}
549
550	return -1;
551}
552
553int slapi_rdn_contains( Slapi_RDN *rdn, const char *type, const char *value, size_t length )
554{
555	return ( slapi_rdn_get_index( rdn, type, value, length ) != -1 );
556}
557
558int slapi_rdn_contains_attr( Slapi_RDN *rdn, const char *type, char **value )
559{
560	return ( slapi_rdn_get_index_attr( rdn, type, value ) != -1 );
561}
562
563int slapi_rdn_compare( Slapi_RDN *rdn1, Slapi_RDN *rdn2 )
564{
565	struct berval nrdn1 = BER_BVNULL;
566	struct berval nrdn2 = BER_BVNULL;
567	int match;
568
569	rdnNormalize( 0, NULL, NULL, (struct berval *)&rdn1->bv, &nrdn1, NULL );
570	rdnNormalize( 0, NULL, NULL, (struct berval *)&rdn2->bv, &nrdn2, NULL );
571
572	if ( rdnMatch( &match, 0, NULL, NULL, &nrdn1, (void *)&nrdn2 ) != LDAP_SUCCESS) {
573		match = -1;
574	}
575
576	return match;
577}
578
579int slapi_rdn_isempty( const Slapi_RDN *rdn )
580{
581	return ( BER_BVISEMPTY( &rdn->bv ) );
582}
583
584int slapi_rdn_add( Slapi_RDN *rdn, const char *type, const char *value )
585{
586	char *s;
587	size_t len;
588
589	len = strlen(type) + 1 + strlen( value );
590	if ( !BER_BVISEMPTY( &rdn->bv ) ) {
591		len += 1 + rdn->bv.bv_len;
592	}
593
594	s = slapi_ch_malloc( len + 1 );
595
596	if ( BER_BVISEMPTY( &rdn->bv ) ) {
597		snprintf( s, len + 1, "%s=%s", type, value );
598	} else {
599		snprintf( s, len + 1, "%s=%s+%s", type, value, rdn->bv.bv_val );
600	}
601
602	slapi_rdn_done( rdn );
603
604	rdn->bv.bv_len = len;
605	rdn->bv.bv_val = s;
606
607	return 1;
608}
609
610int slapi_rdn_remove_index( Slapi_RDN *rdn, int atindex )
611{
612	int count, i;
613
614	count = slapi_rdn_get_num_components( rdn );
615
616	if ( atindex < 0 || atindex >= count )
617		return 0;
618
619	if ( rdn->rdn == NULL )
620		return 0;
621
622	slapi_ch_free_string( &rdn->rdn[atindex]->la_attr.bv_val );
623	slapi_ch_free_string( &rdn->rdn[atindex]->la_value.bv_val );
624
625	for ( i = atindex; i < count; i++ ) {
626		rdn->rdn[i] = rdn->rdn[i + 1];
627	}
628
629	if ( slapi_int_rdn_implode( rdn ) != LDAP_SUCCESS )
630		return 0;
631
632	return 1;
633}
634
635int slapi_rdn_remove( Slapi_RDN *rdn, const char *type, const char *value, size_t length )
636{
637	int index = slapi_rdn_get_index( rdn, type, value, length );
638
639	return slapi_rdn_remove_index( rdn, index );
640}
641
642int slapi_rdn_remove_attr( Slapi_RDN *rdn, const char *type )
643{
644	char *value;
645	int index = slapi_rdn_get_index_attr( rdn, type, &value );
646
647	return slapi_rdn_remove_index( rdn, index );
648}
649
650Slapi_DN *slapi_sdn_add_rdn( Slapi_DN *sdn, const Slapi_RDN *rdn )
651{
652	struct berval bv;
653
654	build_new_dn( &bv, &sdn->dn, (struct berval *)&rdn->bv, NULL );
655
656	slapi_sdn_done( sdn );
657	sdn->dn = bv;
658
659	return sdn;
660}
661
662Slapi_DN *slapi_sdn_set_parent( Slapi_DN *sdn, const Slapi_DN *parentdn )
663{
664	Slapi_RDN rdn;
665
666	slapi_rdn_init_sdn( &rdn, sdn );
667	slapi_sdn_set_dn_byref( sdn, slapi_sdn_get_dn( parentdn ) );
668	slapi_sdn_add_rdn( sdn, &rdn );
669	slapi_rdn_done( &rdn );
670
671	return sdn;
672}
673
674#endif /* LDAP_SLAPI */
675