Home | History | Annotate | Line # | Download | only in overlays
rwmconf.c revision 1.1.1.9
      1 /*	$NetBSD: rwmconf.c,v 1.1.1.9 2021/08/14 16:05:25 christos 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-2021 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.9 2021/08/14 16:05:25 christos 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 );
     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 );
     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 );
    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 );
    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 					Debug(LDAP_DEBUG_ANY,
    193 					      "%s: line %d: source attributeType '%s': %d (%s)\n",
    194 					      fname, lineno, src, rc,
    195 					      text ? text : "null" );
    196 					goto error_return;
    197 				}
    198 
    199 			}
    200 			mapping[1].m_dst_ad = mapping[0].m_src_ad;
    201 		}
    202 
    203 		rc = slap_bv2ad( &mapping[0].m_dst, &mapping[0].m_dst_ad, &text );
    204 		if ( rc != LDAP_SUCCESS ) {
    205 			Debug( LDAP_DEBUG_ANY,
    206 	"%s: line %d: warning, destination attributeType '%s' "
    207 	"is not defined in schema\n",
    208 				fname, lineno, dst );
    209 
    210 			rc = slap_bv2undef_ad( &mapping[0].m_dst,
    211 					&mapping[0].m_dst_ad, &text,
    212 					SLAP_AD_PROXIED );
    213 			if ( rc != LDAP_SUCCESS ) {
    214 				Debug(LDAP_DEBUG_ANY,
    215 				      "%s: line %d: destination attributeType '%s': %d (%s)\n",
    216 				      fname, lineno, dst, rc,
    217 				      text ? text : "null" );
    218 				goto error_return;
    219 			}
    220 		}
    221 		mapping[1].m_src_ad = mapping[0].m_dst_ad;
    222 	}
    223 
    224 	if ( ( src[0] != '\0' && ldap_avl_find( map->map, (caddr_t)mapping, rwm_mapping_cmp ) != NULL)
    225 			|| ldap_avl_find( map->remap, (caddr_t)&mapping[1], rwm_mapping_cmp ) != NULL)
    226 	{
    227 		Debug( LDAP_DEBUG_ANY,
    228 			"%s: line %d: duplicate mapping found.\n",
    229 			fname, lineno );
    230 		/* FIXME: free stuff */
    231 		goto error_return;
    232 	}
    233 
    234 	if ( src[0] != '\0' ) {
    235 		ldap_avl_insert( &map->map, (caddr_t)&mapping[0],
    236 					rwm_mapping_cmp, rwm_mapping_dup );
    237 	}
    238 	ldap_avl_insert( &map->remap, (caddr_t)&mapping[1],
    239 				rwm_mapping_cmp, rwm_mapping_dup );
    240 
    241 success_return:;
    242 	return rc;
    243 
    244 error_return:;
    245 	if ( mapping ) {
    246 		rwm_mapping_free( mapping );
    247 	}
    248 
    249 	return 1;
    250 }
    251 
    252 static char *
    253 rwm_suffix_massage_regexize( const char *s )
    254 {
    255 	char *res, *ptr;
    256 	const char *p, *r;
    257 	int i;
    258 
    259 	if ( s[0] == '\0' ) {
    260 		return ch_strdup( "^(.+)$" );
    261 	}
    262 
    263 	for ( i = 0, p = s;
    264 			( r = strchr( p, ',' ) ) != NULL;
    265 			p = r + 1, i++ )
    266 		;
    267 
    268 	res = ch_calloc( sizeof( char ), strlen( s )
    269 			+ STRLENOF( "((.+),)?" )
    270 			+ STRLENOF( "[ ]?" ) * i
    271 			+ STRLENOF( "$" ) + 1 );
    272 
    273 	ptr = lutil_strcopy( res, "((.+),)?" );
    274 	for ( i = 0, p = s;
    275 			( r = strchr( p, ',' ) ) != NULL;
    276 			p = r + 1 , i++ ) {
    277 		ptr = lutil_strncopy( ptr, p, r - p + 1 );
    278 		ptr = lutil_strcopy( ptr, "[ ]?" );
    279 
    280 		if ( r[ 1 ] == ' ' ) {
    281 			r++;
    282 		}
    283 	}
    284 	ptr = lutil_strcopy( ptr, p );
    285 	ptr[0] = '$';
    286 	ptr[1] = '\0';
    287 
    288 	return res;
    289 }
    290 
    291 static char *
    292 rwm_suffix_massage_patternize( const char *s, const char *p )
    293 {
    294 	ber_len_t	len;
    295 	char		*res, *ptr;
    296 
    297 	len = strlen( p );
    298 
    299 	if ( s[ 0 ] == '\0' ) {
    300 		len++;
    301 	}
    302 
    303 	res = ch_calloc( sizeof( char ), len + STRLENOF( "%1" ) + 1 );
    304 	if ( res == NULL ) {
    305 		return NULL;
    306 	}
    307 
    308 	ptr = lutil_strcopy( res, ( p[0] == '\0' ? "%2" : "%1" ) );
    309 	if ( s[ 0 ] == '\0' ) {
    310 		ptr[ 0 ] = ',';
    311 		ptr++;
    312 	}
    313 	lutil_strcopy( ptr, p );
    314 
    315 	return res;
    316 }
    317 
    318 int
    319 rwm_suffix_massage_config(
    320 		struct rewrite_info *info,
    321 		struct berval *pvnc,
    322 		struct berval *nvnc,
    323 		struct berval *prnc,
    324 		struct berval *nrnc
    325 )
    326 {
    327 	char *rargv[ 5 ];
    328 	int line = 0;
    329 
    330 	rargv[ 0 ] = "rewriteEngine";
    331 	rargv[ 1 ] = "on";
    332 	rargv[ 2 ] = NULL;
    333 	rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
    334 
    335 	rargv[ 0 ] = "rewriteContext";
    336 	rargv[ 1 ] = "default";
    337 	rargv[ 2 ] = NULL;
    338 	rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
    339 
    340 	rargv[ 0 ] = "rewriteRule";
    341 	rargv[ 1 ] = rwm_suffix_massage_regexize( pvnc->bv_val );
    342 	rargv[ 2 ] = rwm_suffix_massage_patternize( pvnc->bv_val, prnc->bv_val );
    343 	rargv[ 3 ] = ":";
    344 	rargv[ 4 ] = NULL;
    345 	rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
    346 	ch_free( rargv[ 1 ] );
    347 	ch_free( rargv[ 2 ] );
    348 
    349 	if ( BER_BVISEMPTY( pvnc ) ) {
    350 		rargv[ 0 ] = "rewriteRule";
    351 		rargv[ 1 ] = "^$";
    352 		rargv[ 2 ] = prnc->bv_val;
    353 		rargv[ 3 ] = ":";
    354 		rargv[ 4 ] = NULL;
    355 		rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
    356 	}
    357 
    358 	rargv[ 0 ] = "rewriteContext";
    359 	rargv[ 1 ] = "searchEntryDN";
    360 	rargv[ 2 ] = NULL;
    361 	rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
    362 
    363 	rargv[ 0 ] = "rewriteRule";
    364 	rargv[ 1 ] = rwm_suffix_massage_regexize( prnc->bv_val );
    365 	rargv[ 2 ] = rwm_suffix_massage_patternize( prnc->bv_val, pvnc->bv_val );
    366 	rargv[ 3 ] = ":";
    367 	rargv[ 4 ] = NULL;
    368 	rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
    369 	ch_free( rargv[ 1 ] );
    370 	ch_free( rargv[ 2 ] );
    371 
    372 	if ( BER_BVISEMPTY( prnc ) ) {
    373 		rargv[ 0 ] = "rewriteRule";
    374 		rargv[ 1 ] = "^$";
    375 		rargv[ 2 ] = pvnc->bv_val;
    376 		rargv[ 3 ] = ":";
    377 		rargv[ 4 ] = NULL;
    378 		rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
    379 	}
    380 
    381 	rargv[ 0 ] = "rewriteContext";
    382 	rargv[ 1 ] = "matchedDN";
    383 	rargv[ 2 ] = "alias";
    384 	rargv[ 3 ] = "searchEntryDN";
    385 	rargv[ 4 ] = NULL;
    386 	rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
    387 
    388 #ifdef RWM_REFERRAL_REWRITE
    389 	/* FIXME: we don't want this on by default, do we? */
    390 	rargv[ 0 ] = "rewriteContext";
    391 	rargv[ 1 ] = "referralDN";
    392 	rargv[ 2 ] = "alias";
    393 	rargv[ 3 ] = "searchEntryDN";
    394 	rargv[ 4 ] = NULL;
    395 	rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
    396 #else /* ! RWM_REFERRAL_REWRITE */
    397 	rargv[ 0 ] = "rewriteContext";
    398 	rargv[ 1 ] = "referralAttrDN";
    399 	rargv[ 2 ] = NULL;
    400 	rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
    401 
    402 	rargv[ 0 ] = "rewriteContext";
    403 	rargv[ 1 ] = "referralDN";
    404 	rargv[ 2 ] = NULL;
    405 	rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
    406 #endif /* ! RWM_REFERRAL_REWRITE */
    407 
    408 	rargv[ 0 ] = "rewriteContext";
    409 	rargv[ 1 ] = "searchAttrDN";
    410 	rargv[ 2 ] = "alias";
    411 	rargv[ 3 ] = "searchEntryDN";
    412 	rargv[ 4 ] = NULL;
    413 	rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
    414 
    415 	return 0;
    416 }
    417 
    418 #endif /* SLAPD_OVER_RWM */
    419