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