1 1.1 christos /* $NetBSD: escapemap.c,v 1.2 2025/09/05 21:16:23 christos Exp $ */ 2 1.1 christos 3 1.1 christos /* $OpenLDAP$ */ 4 1.1 christos /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 5 1.1 christos * 6 1.1 christos * Copyright 2000-2024 The OpenLDAP Foundation. 7 1.1 christos * All rights reserved. 8 1.1 christos * 9 1.1 christos * Redistribution and use in source and binary forms, with or without 10 1.1 christos * modification, are permitted only as authorized by the OpenLDAP 11 1.1 christos * Public License. 12 1.1 christos * 13 1.1 christos * A copy of this license is available in the file LICENSE in the 14 1.1 christos * top-level directory of the distribution or, alternatively, at 15 1.1 christos * <http://www.OpenLDAP.org/license.html>. 16 1.1 christos */ 17 1.1 christos /* ACKNOWLEDGEMENT: 18 1.1 christos * This work was initially developed by Ondej Kuznk for inclusion in OpenLDAP 19 1.1 christos * Software. 20 1.1 christos */ 21 1.1 christos 22 1.1 christos #include <portable.h> 23 1.1 christos 24 1.1 christos #define LDAP_DEPRECATED 1 25 1.1 christos #include "rewrite-int.h" 26 1.1 christos #include "rewrite-map.h" 27 1.1 christos 28 1.1 christos #include <ldap_pvt.h> 29 1.1 christos 30 1.1 christos typedef int (escape_fn)( struct berval *input, struct berval *output ); 31 1.1 christos 32 1.1 christos /* 33 1.1 christos * Map configuration, a NULL-terminated list of escape_fn pointers 34 1.1 christos */ 35 1.1 christos struct escape_map_data { 36 1.1 christos escape_fn **fn; 37 1.1 christos }; 38 1.1 christos 39 1.1 christos /* 40 1.1 christos * (un)escape functions 41 1.1 christos */ 42 1.1 christos 43 1.1 christos static int 44 1.1 christos map_escape_to_filter( struct berval *input, struct berval *output ) 45 1.1 christos { 46 1.1 christos return ldap_bv2escaped_filter_value( input, output ); 47 1.1 christos } 48 1.1 christos 49 1.1 christos static int 50 1.1 christos map_unescape_filter( struct berval *input, struct berval *output ) 51 1.1 christos { 52 1.1 christos ber_slen_t len; 53 1.1 christos 54 1.1 christos if ( ber_dupbv( output, input ) == NULL ) { 55 1.1 christos return REWRITE_ERR; 56 1.1 christos } 57 1.1 christos 58 1.1 christos len = ldap_pvt_filter_value_unescape( output->bv_val ); 59 1.1 christos if ( len < 0 ) { 60 1.1 christos ber_memfree( output->bv_val ); 61 1.1 christos return REWRITE_ERR; 62 1.1 christos } 63 1.1 christos output->bv_len = len; 64 1.1 christos 65 1.1 christos return LDAP_SUCCESS; 66 1.1 christos } 67 1.1 christos 68 1.1 christos static int 69 1.1 christos map_escape_to_dn( struct berval *input, struct berval *output ) 70 1.1 christos { 71 1.1 christos LDAPAVA ava = { .la_attr = BER_BVC("uid"), 72 1.1 christos .la_value = *input, 73 1.1 christos .la_flags = LDAP_AVA_STRING }, 74 1.1 christos *ava_[] = { &ava, NULL }; 75 1.1 christos LDAPRDN rdn[] = { ava_, NULL }; 76 1.1 christos LDAPDN dn = rdn; 77 1.1 christos struct berval dnstr; 78 1.1 christos char *p; 79 1.1 christos int rc; 80 1.1 christos 81 1.1 christos rc = ldap_dn2bv( dn, &dnstr, LDAP_DN_FORMAT_LDAPV3 ); 82 1.1 christos if ( rc != LDAP_SUCCESS ) { 83 1.1 christos return REWRITE_ERR; 84 1.1 christos } 85 1.1 christos 86 1.1 christos p = strchr( dnstr.bv_val, '=' ); 87 1.1 christos p++; 88 1.1 christos 89 1.1 christos output->bv_len = dnstr.bv_len - ( p - dnstr.bv_val ); 90 1.1 christos output->bv_val = malloc( output->bv_len + 1 ); 91 1.1 christos if ( output->bv_val == NULL ) { 92 1.1 christos free( dnstr.bv_val ); 93 1.1 christos return REWRITE_ERR; 94 1.1 christos } 95 1.1 christos memcpy( output->bv_val, p, output->bv_len ); 96 1.1 christos output->bv_val[output->bv_len] = '\0'; 97 1.1 christos 98 1.1 christos free( dnstr.bv_val ); 99 1.1 christos return REWRITE_SUCCESS; 100 1.1 christos } 101 1.1 christos 102 1.1 christos static int 103 1.1 christos map_unescape_dn( struct berval *input, struct berval *output ) 104 1.1 christos { 105 1.1 christos LDAPDN dn; 106 1.1 christos struct berval fake_dn; 107 1.1 christos char *p; 108 1.1 christos int rc = REWRITE_SUCCESS; 109 1.1 christos 110 1.1 christos fake_dn.bv_len = STRLENOF("uid=") + input->bv_len; 111 1.1 christos fake_dn.bv_val = p = malloc( fake_dn.bv_len + 1 ); 112 1.1 christos if ( p == NULL ) { 113 1.1 christos return REWRITE_ERR; 114 1.1 christos } 115 1.1 christos 116 1.1 christos memcpy( p, "uid=", STRLENOF("uid=") ); 117 1.1 christos p += STRLENOF("uid="); 118 1.1 christos memcpy( p, input->bv_val, input->bv_len ); 119 1.1 christos fake_dn.bv_val[fake_dn.bv_len] = '\0'; 120 1.1 christos 121 1.1 christos if ( ldap_bv2dn( &fake_dn, &dn, LDAP_DN_FORMAT_LDAPV3 ) != LDAP_SUCCESS ) { 122 1.1 christos free( fake_dn.bv_val ); 123 1.1 christos return REWRITE_ERR; 124 1.1 christos } 125 1.1 christos if ( ber_dupbv( output, &dn[0][0]->la_value ) == NULL ) { 126 1.1 christos rc = REWRITE_ERR; 127 1.1 christos } 128 1.1 christos ldap_dnfree( dn ); 129 1.1 christos free( fake_dn.bv_val ); 130 1.1 christos return rc; 131 1.1 christos } 132 1.1 christos 133 1.1 christos /* Registered callbacks */ 134 1.1 christos 135 1.1 christos static void * 136 1.1 christos map_escape_parse( 137 1.1 christos const char *fname, 138 1.1 christos int lineno, 139 1.1 christos int argc, 140 1.1 christos char **argv 141 1.1 christos ) 142 1.1 christos { 143 1.1 christos escape_fn **fns; 144 1.1 christos int i; 145 1.1 christos 146 1.1 christos assert( fname != NULL ); 147 1.1 christos assert( argv != NULL ); 148 1.1 christos 149 1.1 christos if ( argc < 1 ) { 150 1.1 christos Debug( LDAP_DEBUG_ANY, 151 1.1 christos "[%s:%d] escape map needs at least one operation\n", 152 1.1 christos fname, lineno ); 153 1.1 christos return NULL; 154 1.1 christos } 155 1.1 christos 156 1.1 christos fns = calloc( sizeof(escape_fn *), argc + 1 ); 157 1.1 christos if ( fns == NULL ) { 158 1.1 christos return NULL; 159 1.1 christos } 160 1.1 christos 161 1.1 christos for ( i = 0; i < argc; i++ ) { 162 1.1 christos if ( strcasecmp( argv[i], "escape2dn" ) == 0 ) { 163 1.1 christos fns[i] = map_escape_to_dn; 164 1.1 christos } else if ( strcasecmp( argv[i], "escape2filter" ) == 0 ) { 165 1.1 christos fns[i] = map_escape_to_filter; 166 1.1 christos } else if ( strcasecmp( argv[i], "unescapedn" ) == 0 ) { 167 1.1 christos fns[i] = map_unescape_dn; 168 1.1 christos } else if ( strcasecmp( argv[i], "unescapefilter" ) == 0 ) { 169 1.1 christos fns[i] = map_unescape_filter; 170 1.1 christos } else { 171 1.1 christos Debug( LDAP_DEBUG_ANY, 172 1.1 christos "[%s:%d] unknown option %s (ignored)\n", 173 1.1 christos fname, lineno, argv[i] ); 174 1.1 christos free( fns ); 175 1.1 christos return NULL; 176 1.1 christos } 177 1.1 christos } 178 1.1 christos 179 1.1 christos return (void *)fns; 180 1.1 christos } 181 1.1 christos 182 1.1 christos static int 183 1.1 christos map_escape_apply( 184 1.1 christos void *private, 185 1.1 christos const char *input, 186 1.1 christos struct berval *output ) 187 1.1 christos { 188 1.1 christos escape_fn **fns = private; 189 1.1 christos struct berval tmpin, tmpout = BER_BVNULL; 190 1.1 christos int i; 191 1.1 christos 192 1.1 christos assert( private != NULL ); 193 1.1 christos assert( input != NULL ); 194 1.1 christos assert( output != NULL ); 195 1.1 christos 196 1.1 christos ber_str2bv( input, 0, 1, &tmpin ); 197 1.1 christos 198 1.1 christos for ( i=0; fns[i]; i++ ) { 199 1.1 christos int rc = fns[i]( &tmpin, &tmpout ); 200 1.1 christos free( tmpin.bv_val ); 201 1.1 christos if ( rc != REWRITE_SUCCESS ) { 202 1.1 christos return rc; 203 1.1 christos } 204 1.1 christos tmpin = tmpout; 205 1.1 christos BER_BVZERO( &tmpout ); 206 1.1 christos } 207 1.1 christos *output = tmpin; 208 1.1 christos 209 1.1 christos return REWRITE_SUCCESS; 210 1.1 christos } 211 1.1 christos 212 1.1 christos static int 213 1.1 christos map_escape_destroy( 214 1.1 christos void *private 215 1.1 christos ) 216 1.1 christos { 217 1.1 christos struct ldap_map_data *data = private; 218 1.1 christos 219 1.1 christos assert( private != NULL ); 220 1.1 christos free( data ); 221 1.1 christos 222 1.1 christos return 0; 223 1.1 christos } 224 1.1 christos 225 1.1 christos const rewrite_mapper rewrite_escape_mapper = { 226 1.1 christos "escape", 227 1.1 christos map_escape_parse, 228 1.1 christos map_escape_apply, 229 1.1 christos map_escape_destroy 230 1.1 christos }; 231