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