1 /*        $NetBSD: rwmconf.c,v 1.3 2021/08/14 16:15: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-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.3 2021/08/14 16:15: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
rwm_map_config(struct ldapmap * oc_map,struct ldapmap * at_map,const char * fname,int lineno,int argc,char ** argv)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 *
rwm_suffix_massage_regexize(const char * s)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 *
rwm_suffix_massage_patternize(const char * s,const char * p)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
rwm_suffix_massage_config(struct rewrite_info * info,struct berval * pvnc,struct berval * nvnc,struct berval * prnc,struct berval * nrnc)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