1 /* $NetBSD: rwmconf.c,v 1.1.1.5 2017/02/09 01:47:02 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-2016 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.5 2017/02/09 01:47:02 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, 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