/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 2000-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* ACKNOWLEDGEMENT: * This work was initially developed by Pierangelo Masarati for * inclusion in OpenLDAP Software. */ #include #include #ifdef HAVE_PWD_H #include #endif #include "rewrite-int.h" #include "rewrite-map.h" static int num_mappers; static const rewrite_mapper **mappers; #define MAPPER_ALLOC 8 struct rewrite_map * rewrite_map_parse( struct rewrite_info *info, const char *string, const char **currpos ) { struct rewrite_map *map = NULL; struct rewrite_subst *subst = NULL; char *s, *begin = NULL, *end; const char *p; int l, cnt, mtx = 0, rc = 0; assert( info != NULL ); assert( string != NULL ); assert( currpos != NULL ); *currpos = NULL; /* * Go to the end of the map invocation (the right closing brace) */ for ( p = string, cnt = 1; p[ 0 ] != '\0' && cnt > 0; p++ ) { if ( IS_REWRITE_SUBMATCH_ESCAPE( p[ 0 ] ) ) { /* * '%' marks the beginning of a new map */ if ( p[ 1 ] == '{' ) { cnt++; /* * '%' followed by a digit may mark the beginning * of an old map */ } else if ( isdigit( (unsigned char) p[ 1 ] ) && p[ 2 ] == '{' ) { cnt++; p++; } if ( p[ 1 ] != '\0' ) { p++; } } else if ( p[ 0 ] == '}' ) { cnt--; } } if ( cnt != 0 ) { return NULL; } *currpos = p; /* * Copy the map invocation */ l = p - string - 1; s = calloc( sizeof( char ), l + 1 ); if ( s == NULL ) { return NULL; } AC_MEMCPY( s, string, l ); s[ l ] = 0; /* * Isolate the map name (except for variable deref) */ switch ( s[ 0 ] ) { case REWRITE_OPERATOR_VARIABLE_GET: case REWRITE_OPERATOR_PARAM_GET: break; default: begin = strchr( s, '(' ); if ( begin == NULL ) { rc = -1; goto cleanup; } begin[ 0 ] = '\0'; begin++; break; } /* * Check for special map types */ p = s; switch ( p[ 0 ] ) { case REWRITE_OPERATOR_SUBCONTEXT: case REWRITE_OPERATOR_COMMAND: case REWRITE_OPERATOR_VARIABLE_SET: case REWRITE_OPERATOR_VARIABLE_GET: case REWRITE_OPERATOR_PARAM_GET: p++; break; } /* * Variable set and get may be repeated to indicate session-wide * instead of operation-wide variables */ switch ( p[ 0 ] ) { case REWRITE_OPERATOR_VARIABLE_SET: case REWRITE_OPERATOR_VARIABLE_GET: p++; break; } /* * Variable get token can be appended to variable set to mean store * AND rewrite */ if ( p[ 0 ] == REWRITE_OPERATOR_VARIABLE_GET ) { p++; } /* * Check the syntax of the variable name */ if ( !isalpha( (unsigned char) p[ 0 ] ) ) { rc = -1; goto cleanup; } for ( p++; p[ 0 ] != '\0'; p++ ) { if ( !isalnum( (unsigned char) p[ 0 ] ) ) { rc = -1; goto cleanup; } } /* * Isolate the argument of the map (except for variable deref) */ switch ( s[ 0 ] ) { case REWRITE_OPERATOR_VARIABLE_GET: case REWRITE_OPERATOR_PARAM_GET: break; default: end = strrchr( begin, ')' ); if ( end == NULL ) { rc = -1; goto cleanup; } end[ 0 ] = '\0'; /* * Compile the substitution pattern of the map argument */ subst = rewrite_subst_compile( info, begin ); if ( subst == NULL ) { rc = -1; goto cleanup; } break; } /* * Create the map */ map = calloc( sizeof( struct rewrite_map ), 1 ); if ( map == NULL ) { rc = -1; goto cleanup; } memset( map, 0, sizeof( struct rewrite_map ) ); #ifdef USE_REWRITE_LDAP_PVT_THREADS if ( ldap_pvt_thread_mutex_init( &map->lm_mutex ) ) { rc = -1; goto cleanup; } ++mtx; #endif /* USE_REWRITE_LDAP_PVT_THREADS */ /* * No subst for variable deref */ switch ( s[ 0 ] ) { case REWRITE_OPERATOR_VARIABLE_GET: case REWRITE_OPERATOR_PARAM_GET: break; default: map->lm_subst = subst; break; } /* * Parses special map types */ switch ( s[ 0 ] ) { /* * Subcontext */ case REWRITE_OPERATOR_SUBCONTEXT: /* '>' */ /* * Fetch the rewrite context * it MUST have been defined previously */ map->lm_type = REWRITE_MAP_SUBCONTEXT; map->lm_name = strdup( s + 1 ); if ( map->lm_name == NULL ) { rc = -1; goto cleanup; } map->lm_data = rewrite_context_find( info, s + 1 ); if ( map->lm_data == NULL ) { rc = -1; goto cleanup; } break; /* * External command (not implemented yet) */ case REWRITE_OPERATOR_COMMAND: /* '|' */ rc = -1; goto cleanup; /* * Variable set */ case REWRITE_OPERATOR_VARIABLE_SET: /* '&' */ if ( s[ 1 ] == REWRITE_OPERATOR_VARIABLE_SET ) { if ( s[ 2 ] == REWRITE_OPERATOR_VARIABLE_GET ) { map->lm_type = REWRITE_MAP_SETW_SESN_VAR; map->lm_name = strdup( s + 3 ); } else { map->lm_type = REWRITE_MAP_SET_SESN_VAR; map->lm_name = strdup( s + 2 ); } } else { if ( s[ 1 ] == REWRITE_OPERATOR_VARIABLE_GET ) { map->lm_type = REWRITE_MAP_SETW_OP_VAR; map->lm_name = strdup( s + 2 ); } else { map->lm_type = REWRITE_MAP_SET_OP_VAR; map->lm_name = strdup( s + 1 ); } } if ( map->lm_name == NULL ) { rc = -1; goto cleanup; } break; /* * Variable dereference */ case REWRITE_OPERATOR_VARIABLE_GET: /* '*' */ if ( s[ 1 ] == REWRITE_OPERATOR_VARIABLE_GET ) { map->lm_type = REWRITE_MAP_GET_SESN_VAR; map->lm_name = strdup( s + 2 ); } else { map->lm_type = REWRITE_MAP_GET_OP_VAR; map->lm_name = strdup( s + 1 ); } if ( map->lm_name == NULL ) { rc = -1; goto cleanup; } break; /* * Parameter */ case REWRITE_OPERATOR_PARAM_GET: /* '$' */ map->lm_type = REWRITE_MAP_GET_PARAM; map->lm_name = strdup( s + 1 ); if ( map->lm_name == NULL ) { rc = -1; goto cleanup; } break; /* * Built-in map */ default: map->lm_type = REWRITE_MAP_BUILTIN; map->lm_name = strdup( s ); if ( map->lm_name == NULL ) { rc = -1; goto cleanup; } map->lm_data = rewrite_builtin_map_find( info, s ); if ( map->lm_data == NULL ) { rc = -1; goto cleanup; } break; } cleanup: free( s ); if ( rc ) { if ( subst != NULL ) { free( subst ); } if ( map ) { #ifdef USE_REWRITE_LDAP_PVT_THREADS if ( mtx ) { ldap_pvt_thread_mutex_destroy( &map->lm_mutex ); } #endif /* USE_REWRITE_LDAP_PVT_THREADS */ if ( map->lm_name ) { free( map->lm_name ); map->lm_name = NULL; } free( map ); map = NULL; } } return map; } /* * Applies the new map type */ int rewrite_map_apply( struct rewrite_info *info, struct rewrite_op *op, struct rewrite_map *map, struct berval *key, struct berval *val ) { int rc = REWRITE_SUCCESS; assert( info != NULL ); assert( op != NULL ); assert( map != NULL ); assert( key != NULL ); assert( val != NULL ); val->bv_val = NULL; val->bv_len = 0; switch ( map->lm_type ) { case REWRITE_MAP_SUBCONTEXT: rc = rewrite_context_apply( info, op, ( struct rewrite_context * )map->lm_data, key->bv_val, &val->bv_val ); if ( val->bv_val != NULL ) { if ( val->bv_val == key->bv_val ) { val->bv_len = key->bv_len; key->bv_val = NULL; } else { val->bv_len = strlen( val->bv_val ); } } break; case REWRITE_MAP_SET_OP_VAR: case REWRITE_MAP_SETW_OP_VAR: rc = rewrite_var_set( &op->lo_vars, map->lm_name, key->bv_val, 1 ) ? REWRITE_SUCCESS : REWRITE_ERR; if ( rc == REWRITE_SUCCESS ) { if ( map->lm_type == REWRITE_MAP_SET_OP_VAR ) { val->bv_val = strdup( "" ); } else { val->bv_val = strdup( key->bv_val ); val->bv_len = key->bv_len; } if ( val->bv_val == NULL ) { rc = REWRITE_ERR; } } break; case REWRITE_MAP_GET_OP_VAR: { struct rewrite_var *var; var = rewrite_var_find( op->lo_vars, map->lm_name ); if ( var == NULL ) { rc = REWRITE_ERR; } else { val->bv_val = strdup( var->lv_value.bv_val ); val->bv_len = var->lv_value.bv_len; if ( val->bv_val == NULL ) { rc = REWRITE_ERR; } } break; } case REWRITE_MAP_SET_SESN_VAR: case REWRITE_MAP_SETW_SESN_VAR: if ( op->lo_cookie == NULL ) { rc = REWRITE_ERR; break; } rc = rewrite_session_var_set( info, op->lo_cookie, map->lm_name, key->bv_val ); if ( rc == REWRITE_SUCCESS ) { if ( map->lm_type == REWRITE_MAP_SET_SESN_VAR ) { val->bv_val = strdup( "" ); } else { val->bv_val = strdup( key->bv_val ); val->bv_len = key->bv_len; } if ( val->bv_val == NULL ) { rc = REWRITE_ERR; } } break; case REWRITE_MAP_GET_SESN_VAR: rc = rewrite_session_var_get( info, op->lo_cookie, map->lm_name, val ); break; case REWRITE_MAP_GET_PARAM: rc = rewrite_param_get( info, map->lm_name, val ); break; case REWRITE_MAP_BUILTIN: { struct rewrite_builtin_map *bmap = map->lm_data; if ( bmap->lb_mapper && bmap->lb_mapper->rm_apply ) rc = bmap->lb_mapper->rm_apply( bmap->lb_private, key->bv_val, val ); else rc = REWRITE_ERR; break; } default: rc = REWRITE_ERR; break; } return rc; } void rewrite_builtin_map_free( void *tmp ) { struct rewrite_builtin_map *map = ( struct rewrite_builtin_map * )tmp; assert( map != NULL ); if ( map->lb_mapper && map->lb_mapper->rm_destroy ) map->lb_mapper->rm_destroy( map->lb_private ); free( map->lb_name ); free( map ); } int rewrite_map_destroy( struct rewrite_map **pmap ) { struct rewrite_map *map; assert( pmap != NULL ); assert( *pmap != NULL ); map = *pmap; #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_mutex_lock( &map->lm_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ if ( map->lm_name ) { free( map->lm_name ); map->lm_name = NULL; } if ( map->lm_subst ) { rewrite_subst_destroy( &map->lm_subst ); } #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_mutex_unlock( &map->lm_mutex ); ldap_pvt_thread_mutex_destroy( &map->lm_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ free( map ); *pmap = NULL; return 0; } /* ldapmap.c */ extern const rewrite_mapper rewrite_ldap_mapper; /* escapemap.c */ extern const rewrite_mapper rewrite_escape_mapper; const rewrite_mapper * rewrite_mapper_find( const char *name ) { int i; if ( !strcasecmp( name, "ldap" )) return &rewrite_ldap_mapper; if ( !strcasecmp( name, "escape" )) return &rewrite_escape_mapper; for (i=0; irm_name )) return mappers[i]; return NULL; } int rewrite_mapper_register( const rewrite_mapper *map ) { if ( num_mappers % MAPPER_ALLOC == 0 ) { const rewrite_mapper **mnew; mnew = realloc( mappers, (num_mappers + MAPPER_ALLOC) * sizeof( rewrite_mapper * )); if ( mnew ) mappers = mnew; else return -1; } mappers[num_mappers++] = map; return 0; } int rewrite_mapper_unregister( const rewrite_mapper *map ) { int i; for (i = 0; i