Home | History | Annotate | Line # | Download | only in overlays
rwmconf.c revision 1.1.1.6.4.1
      1 /*	$NetBSD: rwmconf.c,v 1.1.1.6.4.1 2020/04/13 07:56:21 martin Exp $	*/
      2 
      3 /* rwmconf.c - rewrite/map configuration file routines */
      4 /* $OpenLDAP$ */
      5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      6  *
      7  * Copyright 1999-2019 The OpenLDAP Foundation.
      8  * Portions Copyright 1999-2003 Howard Chu.
      9  * Portions Copyright 2000-2003 Pierangelo Masarati.
     10  * All rights reserved.
     11  *
     12  * Redistribution and use in source and binary forms, with or without
     13  * modification, are permitted only as authorized by the OpenLDAP
     14  * Public License.
     15  *
     16  * A copy of this license is available in the file LICENSE in the
     17  * top-level directory of the distribution or, alternatively, at
     18  * <http://www.OpenLDAP.org/license.html>.
     19  */
     20 /* ACKNOWLEDGEMENTS:
     21  * This work was initially developed by the Howard Chu for inclusion
     22  * in OpenLDAP Software and subsequently enhanced by Pierangelo
     23  * Masarati.
     24  */
     25 
     26 #include <sys/cdefs.h>
     27 __RCSID("$NetBSD: rwmconf.c,v 1.1.1.6.4.1 2020/04/13 07:56:21 martin Exp $");
     28 
     29 #include "portable.h"
     30 
     31 #ifdef SLAPD_OVER_RWM
     32 
     33 #include <stdio.h>
     34 
     35 #include <ac/string.h>
     36 #include <ac/socket.h>
     37 
     38 #include "slap.h"
     39 #include "rwm.h"
     40 #include "lutil.h"
     41 
     42 int
     43 rwm_map_config(
     44 		struct ldapmap	*oc_map,
     45 		struct ldapmap	*at_map,
     46 		const char	*fname,
     47 		int		lineno,
     48 		int		argc,
     49 		char		**argv )
     50 {
     51 	struct ldapmap		*map;
     52 	struct ldapmapping	*mapping;
     53 	char			*src, *dst;
     54 	int			is_oc = 0;
     55 	int			rc = 0;
     56 
     57 	if ( argc < 3 || argc > 4 ) {
     58 		Debug( LDAP_DEBUG_ANY,
     59 	"%s: line %d: syntax is \"map {objectclass | attribute} [<local> | *] {<foreign> | *}\"\n",
     60 			fname, lineno, 0 );
     61 		return 1;
     62 	}
     63 
     64 	if ( strcasecmp( argv[1], "objectclass" ) == 0 ) {
     65 		map = oc_map;
     66 		is_oc = 1;
     67 
     68 	} else if ( strcasecmp( argv[1], "attribute" ) == 0 ) {
     69 		map = at_map;
     70 
     71 	} else {
     72 		Debug( LDAP_DEBUG_ANY, "%s: line %d: syntax is "
     73 			"\"map {objectclass | attribute} [<local> | *] "
     74 			"{<foreign> | *}\"\n",
     75 			fname, lineno, 0 );
     76 		return 1;
     77 	}
     78 
     79 	if ( !is_oc && map->map == NULL ) {
     80 		/* only init if required */
     81 		if ( rwm_map_init( map, &mapping ) != LDAP_SUCCESS ) {
     82 			return 1;
     83 		}
     84 	}
     85 
     86 	if ( strcmp( argv[2], "*" ) == 0 ) {
     87 		if ( argc < 4 || strcmp( argv[3], "*" ) == 0 ) {
     88 			map->drop_missing = ( argc < 4 );
     89 			goto success_return;
     90 		}
     91 		src = dst = argv[3];
     92 
     93 	} else if ( argc < 4 ) {
     94 		src = "";
     95 		dst = argv[2];
     96 
     97 	} else {
     98 		src = argv[2];
     99 		dst = ( strcmp( argv[3], "*" ) == 0 ? src : argv[3] );
    100 	}
    101 
    102 	if ( ( map == at_map )
    103 			&& ( strcasecmp( src, "objectclass" ) == 0
    104 			|| strcasecmp( dst, "objectclass" ) == 0 ) )
    105 	{
    106 		Debug( LDAP_DEBUG_ANY,
    107 			"%s: line %d: objectclass attribute cannot be mapped\n",
    108 			fname, lineno, 0 );
    109 		return 1;
    110 	}
    111 
    112 	mapping = (struct ldapmapping *)ch_calloc( 2,
    113 		sizeof(struct ldapmapping) );
    114 	if ( mapping == NULL ) {
    115 		Debug( LDAP_DEBUG_ANY,
    116 			"%s: line %d: out of memory\n",
    117 			fname, lineno, 0 );
    118 		return 1;
    119 	}
    120 	ber_str2bv( src, 0, 1, &mapping[0].m_src );
    121 	ber_str2bv( dst, 0, 1, &mapping[0].m_dst );
    122 	mapping[1].m_src = mapping[0].m_dst;
    123 	mapping[1].m_dst = mapping[0].m_src;
    124 
    125 	mapping[0].m_flags = RWMMAP_F_NONE;
    126 	mapping[1].m_flags = RWMMAP_F_NONE;
    127 
    128 	/*
    129 	 * schema check
    130 	 */
    131 	if ( is_oc ) {
    132 		if ( src[0] != '\0' ) {
    133 			mapping[0].m_src_oc = oc_bvfind( &mapping[0].m_src );
    134 			if ( mapping[0].m_src_oc == NULL ) {
    135 				Debug( LDAP_DEBUG_ANY,
    136 	"%s: line %d: warning, source objectClass '%s' "
    137 	"should be defined in schema\n",
    138 					fname, lineno, src );
    139 
    140 				/*
    141 				 * FIXME: this should become an err
    142 				 */
    143 				mapping[0].m_src_oc = ch_malloc( sizeof( ObjectClass ) );
    144 				memset( mapping[0].m_src_oc, 0, sizeof( ObjectClass ) );
    145 				mapping[0].m_src_oc->soc_cname = mapping[0].m_src;
    146 				mapping[0].m_flags |= RWMMAP_F_FREE_SRC;
    147 			}
    148 			mapping[1].m_dst_oc = mapping[0].m_src_oc;
    149 		}
    150 
    151 		mapping[0].m_dst_oc = oc_bvfind( &mapping[0].m_dst );
    152 		if ( mapping[0].m_dst_oc == NULL ) {
    153 			Debug( LDAP_DEBUG_ANY,
    154 	"%s: line %d: warning, destination objectClass '%s' "
    155 	"is not defined in schema\n",
    156 				fname, lineno, dst );
    157 
    158 			mapping[0].m_dst_oc = oc_bvfind_undef( &mapping[0].m_dst );
    159 			if ( mapping[0].m_dst_oc == NULL ) {
    160 				Debug( LDAP_DEBUG_ANY, "%s: line %d: unable to mimic destination objectClass '%s'\n",
    161 					fname, lineno, dst );
    162 				goto error_return;
    163 			}
    164 		}
    165 		mapping[1].m_src_oc = mapping[0].m_dst_oc;
    166 
    167 		mapping[0].m_flags |= RWMMAP_F_IS_OC;
    168 		mapping[1].m_flags |= RWMMAP_F_IS_OC;
    169 
    170 	} else {
    171 		int			rc;
    172 		const char		*text = NULL;
    173 
    174 		if ( src[0] != '\0' ) {
    175 			rc = slap_bv2ad( &mapping[0].m_src,
    176 					&mapping[0].m_src_ad, &text );
    177 			if ( rc != LDAP_SUCCESS ) {
    178 				Debug( LDAP_DEBUG_ANY,
    179 	"%s: line %d: warning, source attributeType '%s' "
    180 	"should be defined in schema\n",
    181 					fname, lineno, src );
    182 
    183 				/*
    184 				 * we create a fake "proxied" ad
    185 				 * and add it here.
    186 				 */
    187 
    188 				rc = slap_bv2undef_ad( &mapping[0].m_src,
    189 						&mapping[0].m_src_ad, &text,
    190 						SLAP_AD_PROXIED );
    191 				if ( rc != LDAP_SUCCESS ) {
    192 					char prefix[1024];
    193 					snprintf( prefix, sizeof(prefix),
    194 	"%s: line %d: source attributeType '%s': %d",
    195 						fname, lineno, src, rc );
    196 					Debug( LDAP_DEBUG_ANY, "%s (%s)\n",
    197 						prefix, text ? text : "null", 0 );
    198 					goto error_return;
    199 				}
    200 
    201 			}
    202 			mapping[1].m_dst_ad = mapping[0].m_src_ad;
    203 		}
    204 
    205 		rc = slap_bv2ad( &mapping[0].m_dst, &mapping[0].m_dst_ad, &text );
    206 		if ( rc != LDAP_SUCCESS ) {
    207 			Debug( LDAP_DEBUG_ANY,
    208 	"%s: line %d: warning, destination attributeType '%s' "
    209 	"is not defined in schema\n",
    210 				fname, lineno, dst );
    211 
    212 			rc = slap_bv2undef_ad( &mapping[0].m_dst,
    213 					&mapping[0].m_dst_ad, &text,
    214 					SLAP_AD_PROXIED );
    215 			if ( rc != LDAP_SUCCESS ) {
    216 				char prefix[1024];
    217 				snprintf( prefix, sizeof(prefix),
    218 	"%s: line %d: destination attributeType '%s': %d",
    219 					fname, lineno, dst, rc );
    220 				Debug( LDAP_DEBUG_ANY, "%s (%s)\n",
    221 					prefix, text ? text : "null", 0 );
    222 				goto error_return;
    223 			}
    224 		}
    225 		mapping[1].m_src_ad = mapping[0].m_dst_ad;
    226 	}
    227 
    228 	if ( ( src[0] != '\0' && avl_find( map->map, (caddr_t)mapping, rwm_mapping_cmp ) != NULL)
    229 			|| avl_find( map->remap, (caddr_t)&mapping[1], rwm_mapping_cmp ) != NULL)
    230 	{
    231 		Debug( LDAP_DEBUG_ANY,
    232 			"%s: line %d: duplicate mapping found.\n",
    233 			fname, lineno, 0 );
    234 		/* FIXME: free stuff */
    235 		goto error_return;
    236 	}
    237 
    238 	if ( src[0] != '\0' ) {
    239 		avl_insert( &map->map, (caddr_t)&mapping[0],
    240 					rwm_mapping_cmp, rwm_mapping_dup );
    241 	}
    242 	avl_insert( &map->remap, (caddr_t)&mapping[1],
    243 				rwm_mapping_cmp, rwm_mapping_dup );
    244 
    245 success_return:;
    246 	return rc;
    247 
    248 error_return:;
    249 	if ( mapping ) {
    250 		rwm_mapping_free( mapping );
    251 	}
    252 
    253 	return 1;
    254 }
    255 
    256 static char *
    257 rwm_suffix_massage_regexize( const char *s )
    258 {
    259 	char *res, *ptr;
    260 	const char *p, *r;
    261 	int i;
    262 
    263 	if ( s[0] == '\0' ) {
    264 		return ch_strdup( "^(.+)$" );
    265 	}
    266 
    267 	for ( i = 0, p = s;
    268 			( r = strchr( p, ',' ) ) != NULL;
    269 			p = r + 1, i++ )
    270 		;
    271 
    272 	res = ch_calloc( sizeof( char ), strlen( s )
    273 			+ STRLENOF( "((.+),)?" )
    274 			+ STRLENOF( "[ ]?" ) * i
    275 			+ STRLENOF( "$" ) + 1 );
    276 
    277 	ptr = lutil_strcopy( res, "((.+),)?" );
    278 	for ( i = 0, p = s;
    279 			( r = strchr( p, ',' ) ) != NULL;
    280 			p = r + 1 , i++ ) {
    281 		ptr = lutil_strncopy( ptr, p, r - p + 1 );
    282 		ptr = lutil_strcopy( ptr, "[ ]?" );
    283 
    284 		if ( r[ 1 ] == ' ' ) {
    285 			r++;
    286 		}
    287 	}
    288 	ptr = lutil_strcopy( ptr, p );
    289 	ptr[0] = '$';
    290 	ptr[1] = '\0';
    291 
    292 	return res;
    293 }
    294 
    295 static char *
    296 rwm_suffix_massage_patternize( const char *s, const char *p )
    297 {
    298 	ber_len_t	len;
    299 	char		*res, *ptr;
    300 
    301 	len = strlen( p );
    302 
    303 	if ( s[ 0 ] == '\0' ) {
    304 		len++;
    305 	}
    306 
    307 	res = ch_calloc( sizeof( char ), len + STRLENOF( "%1" ) + 1 );
    308 	if ( res == NULL ) {
    309 		return NULL;
    310 	}
    311 
    312 	ptr = lutil_strcopy( res, ( p[0] == '\0' ? "%2" : "%1" ) );
    313 	if ( s[ 0 ] == '\0' ) {
    314 		ptr[ 0 ] = ',';
    315 		ptr++;
    316 	}
    317 	lutil_strcopy( ptr, p );
    318 
    319 	return res;
    320 }
    321 
    322 int
    323 rwm_suffix_massage_config(
    324 		struct rewrite_info *info,
    325 		struct berval *pvnc,
    326 		struct berval *nvnc,
    327 		struct berval *prnc,
    328 		struct berval *nrnc
    329 )
    330 {
    331 	char *rargv[ 5 ];
    332 	int line = 0;
    333 
    334 	rargv[ 0 ] = "rewriteEngine";
    335 	rargv[ 1 ] = "on";
    336 	rargv[ 2 ] = NULL;
    337 	rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
    338 
    339 	rargv[ 0 ] = "rewriteContext";
    340 	rargv[ 1 ] = "default";
    341 	rargv[ 2 ] = NULL;
    342 	rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
    343 
    344 	rargv[ 0 ] = "rewriteRule";
    345 	rargv[ 1 ] = rwm_suffix_massage_regexize( pvnc->bv_val );
    346 	rargv[ 2 ] = rwm_suffix_massage_patternize( pvnc->bv_val, prnc->bv_val );
    347 	rargv[ 3 ] = ":";
    348 	rargv[ 4 ] = NULL;
    349 	rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
    350 	ch_free( rargv[ 1 ] );
    351 	ch_free( rargv[ 2 ] );
    352 
    353 	if ( BER_BVISEMPTY( pvnc ) ) {
    354 		rargv[ 0 ] = "rewriteRule";
    355 		rargv[ 1 ] = "^$";
    356 		rargv[ 2 ] = prnc->bv_val;
    357 		rargv[ 3 ] = ":";
    358 		rargv[ 4 ] = NULL;
    359 		rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
    360 	}
    361 
    362 	rargv[ 0 ] = "rewriteContext";
    363 	rargv[ 1 ] = "searchEntryDN";
    364 	rargv[ 2 ] = NULL;
    365 	rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
    366 
    367 	rargv[ 0 ] = "rewriteRule";
    368 	rargv[ 1 ] = rwm_suffix_massage_regexize( prnc->bv_val );
    369 	rargv[ 2 ] = rwm_suffix_massage_patternize( prnc->bv_val, pvnc->bv_val );
    370 	rargv[ 3 ] = ":";
    371 	rargv[ 4 ] = NULL;
    372 	rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
    373 	ch_free( rargv[ 1 ] );
    374 	ch_free( rargv[ 2 ] );
    375 
    376 	if ( BER_BVISEMPTY( prnc ) ) {
    377 		rargv[ 0 ] = "rewriteRule";
    378 		rargv[ 1 ] = "^$";
    379 		rargv[ 2 ] = pvnc->bv_val;
    380 		rargv[ 3 ] = ":";
    381 		rargv[ 4 ] = NULL;
    382 		rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
    383 	}
    384 
    385 	rargv[ 0 ] = "rewriteContext";
    386 	rargv[ 1 ] = "matchedDN";
    387 	rargv[ 2 ] = "alias";
    388 	rargv[ 3 ] = "searchEntryDN";
    389 	rargv[ 4 ] = NULL;
    390 	rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
    391 
    392 #ifdef RWM_REFERRAL_REWRITE
    393 	/* FIXME: we don't want this on by default, do we? */
    394 	rargv[ 0 ] = "rewriteContext";
    395 	rargv[ 1 ] = "referralDN";
    396 	rargv[ 2 ] = "alias";
    397 	rargv[ 3 ] = "searchEntryDN";
    398 	rargv[ 4 ] = NULL;
    399 	rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
    400 #else /* ! RWM_REFERRAL_REWRITE */
    401 	rargv[ 0 ] = "rewriteContext";
    402 	rargv[ 1 ] = "referralAttrDN";
    403 	rargv[ 2 ] = NULL;
    404 	rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
    405 
    406 	rargv[ 0 ] = "rewriteContext";
    407 	rargv[ 1 ] = "referralDN";
    408 	rargv[ 2 ] = NULL;
    409 	rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
    410 #endif /* ! RWM_REFERRAL_REWRITE */
    411 
    412 	rargv[ 0 ] = "rewriteContext";
    413 	rargv[ 1 ] = "searchAttrDN";
    414 	rargv[ 2 ] = "alias";
    415 	rargv[ 3 ] = "searchEntryDN";
    416 	rargv[ 4 ] = NULL;
    417 	rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
    418 
    419 	return 0;
    420 }
    421 
    422 #endif /* SLAPD_OVER_RWM */
    423