Home | History | Annotate | Line # | Download | only in librewrite
      1 /*	$NetBSD: xmap.c,v 1.4 2025/09/05 21:16:23 christos Exp $	*/
      2 
      3 /* $OpenLDAP$ */
      4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      5  *
      6  * Copyright 2000-2024 The OpenLDAP Foundation.
      7  * All rights reserved.
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted only as authorized by the OpenLDAP
     11  * Public License.
     12  *
     13  * A copy of this license is available in the file LICENSE in the
     14  * top-level directory of the distribution or, alternatively, at
     15  * <http://www.OpenLDAP.org/license.html>.
     16  */
     17 /* ACKNOWLEDGEMENT:
     18  * This work was initially developed by Pierangelo Masarati for
     19  * inclusion in OpenLDAP Software.
     20  */
     21 
     22 #include <portable.h>
     23 
     24 #include <stdio.h>
     25 
     26 #ifdef HAVE_PWD_H
     27 #include <pwd.h>
     28 #endif
     29 
     30 #define LDAP_DEPRECATED 1
     31 #include "rewrite-int.h"
     32 #include "rewrite-map.h"
     33 
     34 /*
     35  * Global data
     36  */
     37 #ifdef USE_REWRITE_LDAP_PVT_THREADS
     38 ldap_pvt_thread_mutex_t xpasswd_mutex;
     39 static int xpasswd_mutex_init = 0;
     40 #endif /* USE_REWRITE_LDAP_PVT_THREADS */
     41 
     42 /*
     43  * Map parsing
     44  * NOTE: these are old-fashion maps; new maps will be parsed on separate
     45  * config lines, and referred by name.
     46  */
     47 struct rewrite_map *
     48 rewrite_xmap_parse(
     49 		struct rewrite_info *info,
     50 		const char *s,
     51 		const char **currpos
     52 )
     53 {
     54 	struct rewrite_map *map;
     55 
     56 	assert( info != NULL );
     57 	assert( s != NULL );
     58 	assert( currpos != NULL );
     59 
     60 	Debug( LDAP_DEBUG_ARGS, "rewrite_xmap_parse: %s\n",
     61 			s );
     62 
     63 	*currpos = NULL;
     64 
     65 	map = calloc( sizeof( struct rewrite_map ), 1 );
     66 	if ( map == NULL ) {
     67 		Debug( LDAP_DEBUG_ANY, "rewrite_xmap_parse:"
     68 				" calloc failed\n" );
     69 		return NULL;
     70 	}
     71 
     72 	/*
     73 	 * Experimental passwd map:
     74 	 * replaces the uid with the matching gecos from /etc/passwd file
     75 	 */
     76 	if ( strncasecmp(s, "xpasswd", 7 ) == 0 ) {
     77 		map->lm_type = REWRITE_MAP_XPWDMAP;
     78 		map->lm_name = strdup( "xpasswd" );
     79 		if ( map->lm_name == NULL ) {
     80 			free( map );
     81 			return NULL;
     82 		}
     83 
     84 		assert( s[7] == '}' );
     85 		*currpos = s + 8;
     86 
     87 #ifdef USE_REWRITE_LDAP_PVT_THREADS
     88 		if ( !xpasswd_mutex_init ) {
     89 			if ( ldap_pvt_thread_mutex_init( &xpasswd_mutex ) ) {
     90 				free( map );
     91 				return NULL;
     92 			}
     93 		}
     94 		++xpasswd_mutex_init;
     95 #endif /* USE_REWRITE_LDAP_PVT_THREADS */
     96 
     97 		/* Don't really care if fails */
     98 		return map;
     99 
    100 	/*
    101 	 * Experimental file map:
    102 	 * looks up key in a `key value' ascii file
    103 	 */
    104 	} else if ( strncasecmp( s, "xfile", 5 ) == 0 ) {
    105 		char *filename;
    106 		const char *p;
    107 		int l;
    108 		int c = 5;
    109 
    110 		map->lm_type = REWRITE_MAP_XFILEMAP;
    111 
    112 		if ( s[ c ] != '(' ) {
    113 			free( map );
    114 			return NULL;
    115 		}
    116 
    117 		/* Must start with '/' for security concerns */
    118 		c++;
    119 		if ( s[ c ] != '/' ) {
    120 			free( map );
    121 			return NULL;
    122 		}
    123 
    124 		for ( p = s + c; p[ 0 ] != '\0' && p[ 0 ] != ')'; p++ );
    125 		if ( p[ 0 ] != ')' ) {
    126 			free( map );
    127 			return NULL;
    128 		}
    129 
    130 		l = p - s - c;
    131 		filename = calloc( sizeof( char ), l + 1 );
    132 		if ( filename == NULL ) {
    133 			free( map );
    134 			return NULL;
    135 		}
    136 		AC_MEMCPY( filename, s + c, l );
    137 		filename[ l ] = '\0';
    138 
    139 		map->lm_args = ( void * )fopen( filename, "r" );
    140 		free( filename );
    141 
    142 		if ( map->lm_args == NULL ) {
    143 			free( map );
    144 			return NULL;
    145 		}
    146 
    147 		*currpos = p + 1;
    148 
    149 #ifdef USE_REWRITE_LDAP_PVT_THREADS
    150                 if ( ldap_pvt_thread_mutex_init( &map->lm_mutex ) ) {
    151 			fclose( ( FILE * )map->lm_args );
    152 			free( map );
    153 			return NULL;
    154 		}
    155 #endif /* USE_REWRITE_LDAP_PVT_THREADS */
    156 
    157 		return map;
    158 
    159 	/*
    160          * Experimental ldap map:
    161          * looks up key on the fly (not implemented!)
    162          */
    163         } else if ( strncasecmp(s, "xldap", 5 ) == 0 ) {
    164 		char *p;
    165 		char *url;
    166 		int l, rc;
    167 		int c = 5;
    168 		LDAPURLDesc *lud;
    169 
    170 		if ( s[ c ] != '(' ) {
    171 			free( map );
    172 			return NULL;
    173 		}
    174 		c++;
    175 
    176 		p = strchr( s, '}' );
    177 		if ( p == NULL ) {
    178 			free( map );
    179 			return NULL;
    180 		}
    181 		p--;
    182 
    183 		*currpos = p + 2;
    184 
    185 		/*
    186 		 * Add two bytes for urlencoding of '%s'
    187 		 */
    188 		l = p - s - c;
    189 		url = calloc( sizeof( char ), l + 3 );
    190 		if ( url == NULL ) {
    191 			free( map );
    192 			return NULL;
    193 		}
    194 		AC_MEMCPY( url, s + c, l );
    195 		url[ l ] = '\0';
    196 
    197 		/*
    198 		 * Urlencodes the '%s' for ldap_url_parse
    199 		 */
    200 		p = strchr( url, '%' );
    201 		if ( p != NULL ) {
    202 			AC_MEMCPY( p + 3, p + 1, strlen( p + 1 ) + 1 );
    203 			p[ 1 ] = '2';
    204 			p[ 2 ] = '5';
    205 		}
    206 
    207 		rc =  ldap_url_parse( url, &lud );
    208 		free( url );
    209 
    210 		if ( rc != LDAP_SUCCESS ) {
    211 			free( map );
    212 			return NULL;
    213 		}
    214 		assert( lud != NULL );
    215 
    216 		map->lm_args = ( void * )lud;
    217 		map->lm_type = REWRITE_MAP_XLDAPMAP;
    218 
    219 #ifdef USE_REWRITE_LDAP_PVT_THREADS
    220                 if ( ldap_pvt_thread_mutex_init( &map->lm_mutex ) ) {
    221 			ldap_free_urldesc( lud );
    222 			free( map );
    223 			return NULL;
    224 		}
    225 #endif /* USE_REWRITE_LDAP_PVT_THREADS */
    226 
    227 		return map;
    228 
    229 	/* Unhandled map */
    230 	}
    231 
    232 	free( map );
    233 	return NULL;
    234 }
    235 
    236 /*
    237  * Map key -> value resolution
    238  * NOTE: these are old-fashion maps; new maps will be parsed on separate
    239  * config lines, and referred by name.
    240  */
    241 int
    242 rewrite_xmap_apply(
    243 		struct rewrite_info *info,
    244 		struct rewrite_op *op,
    245 		struct rewrite_map *map,
    246 		struct berval *key,
    247 		struct berval *val
    248 )
    249 {
    250 	int rc = REWRITE_SUCCESS;
    251 
    252 	assert( info != NULL );
    253 	assert( op != NULL );
    254 	assert( map != NULL );
    255 	assert( key != NULL );
    256 	assert( val != NULL );
    257 
    258 	val->bv_val = NULL;
    259 	val->bv_len = 0;
    260 
    261 	switch ( map->lm_type ) {
    262 #ifdef HAVE_GETPWNAM
    263 	case REWRITE_MAP_XPWDMAP: {
    264 		struct passwd *pwd;
    265 
    266 #ifdef USE_REWRITE_LDAP_PVT_THREADS
    267 		ldap_pvt_thread_mutex_lock( &xpasswd_mutex );
    268 #endif /* USE_REWRITE_LDAP_PVT_THREADS */
    269 
    270 		pwd = getpwnam( key->bv_val );
    271 		if ( pwd == NULL ) {
    272 
    273 #ifdef USE_REWRITE_LDAP_PVT_THREADS
    274 			ldap_pvt_thread_mutex_unlock( &xpasswd_mutex );
    275 #endif /* USE_REWRITE_LDAP_PVT_THREADS */
    276 
    277 			rc = LDAP_NO_SUCH_OBJECT;
    278 			break;
    279 		}
    280 
    281 #ifdef HAVE_STRUCT_PASSWD_PW_GECOS
    282 		if ( pwd->pw_gecos != NULL && pwd->pw_gecos[0] != '\0' ) {
    283 			int l = strlen( pwd->pw_gecos );
    284 
    285 			val->bv_val = strdup( pwd->pw_gecos );
    286 			val->bv_len = l;
    287 		} else
    288 #endif /* HAVE_STRUCT_PASSWD_PW_GECOS */
    289 		{
    290 			val->bv_val = strdup( key->bv_val );
    291 			val->bv_len = key->bv_len;
    292 		}
    293 
    294 #ifdef USE_REWRITE_LDAP_PVT_THREADS
    295 		ldap_pvt_thread_mutex_unlock( &xpasswd_mutex );
    296 #endif /* USE_REWRITE_LDAP_PVT_THREADS */
    297 
    298 		if ( val->bv_val == NULL ) {
    299 			rc = REWRITE_ERR;
    300 		}
    301 		break;
    302 	}
    303 #endif /* HAVE_GETPWNAM*/
    304 
    305 	case REWRITE_MAP_XFILEMAP: {
    306 		char buf[1024];
    307 
    308 		if ( map->lm_args == NULL ) {
    309 			rc = REWRITE_ERR;
    310 			break;
    311 		}
    312 
    313 #ifdef USE_REWRITE_LDAP_PVT_THREADS
    314 		ldap_pvt_thread_mutex_lock( &map->lm_mutex );
    315 #endif /* USE_REWRITE_LDAP_PVT_THREADS */
    316 
    317 		rewind( ( FILE * )map->lm_args );
    318 
    319 		while ( fgets( buf, sizeof( buf ), ( FILE * )map->lm_args ) ) {
    320 			char *p;
    321 			int blen;
    322 
    323 			blen = strlen( buf );
    324 			if ( buf[ blen - 1 ] == '\n' ) {
    325 				buf[ blen - 1 ] = '\0';
    326 			}
    327 
    328 			p = strtok( buf, " " );
    329 			if ( p == NULL ) {
    330 #ifdef USE_REWRITE_LDAP_PVT_THREADS
    331 				ldap_pvt_thread_mutex_unlock( &map->lm_mutex );
    332 #endif /* USE_REWRITE_LDAP_PVT_THREADS */
    333 				rc = REWRITE_ERR;
    334 				goto rc_return;
    335 			}
    336 			if ( strcasecmp( p, key->bv_val ) == 0
    337 					&& ( p = strtok( NULL, "" ) ) ) {
    338 				val->bv_val = strdup( p );
    339 				if ( val->bv_val == NULL ) {
    340 #ifdef USE_REWRITE_LDAP_PVT_THREADS
    341 					ldap_pvt_thread_mutex_unlock( &map->lm_mutex );
    342 #endif /* USE_REWRITE_LDAP_PVT_THREADS */
    343 					rc = REWRITE_ERR;
    344 					goto rc_return;
    345 				}
    346 
    347 				val->bv_len = strlen( p );
    348 
    349 #ifdef USE_REWRITE_LDAP_PVT_THREADS
    350 				ldap_pvt_thread_mutex_unlock( &map->lm_mutex );
    351 #endif /* USE_REWRITE_LDAP_PVT_THREADS */
    352 
    353 				goto rc_return;
    354 			}
    355 		}
    356 
    357 #ifdef USE_REWRITE_LDAP_PVT_THREADS
    358 		ldap_pvt_thread_mutex_unlock( &map->lm_mutex );
    359 #endif /* USE_REWRITE_LDAP_PVT_THREADS */
    360 
    361 		rc = REWRITE_ERR;
    362 
    363 		break;
    364 	}
    365 
    366 	case REWRITE_MAP_XLDAPMAP: {
    367 		LDAP *ld;
    368 		char filter[1024];
    369 		LDAPMessage *res = NULL, *entry;
    370 		LDAPURLDesc *lud = ( LDAPURLDesc * )map->lm_args;
    371 		int attrsonly = 0;
    372 		char **values;
    373 
    374 		assert( lud != NULL );
    375 
    376 		/*
    377 		 * No mutex because there is no write on the map data
    378 		 */
    379 
    380 		ld = ldap_init( lud->lud_host, lud->lud_port );
    381 		if ( ld == NULL ) {
    382 			rc = REWRITE_ERR;
    383 			goto rc_return;
    384 		}
    385 
    386 		snprintf( filter, sizeof( filter ), lud->lud_filter,
    387 				key->bv_val );
    388 
    389 		if ( strcasecmp( lud->lud_attrs[ 0 ], "dn" ) == 0 ) {
    390 			attrsonly = 1;
    391 		}
    392 		rc = ldap_search_s( ld, lud->lud_dn, lud->lud_scope,
    393 				filter, lud->lud_attrs, attrsonly, &res );
    394 		if ( rc != LDAP_SUCCESS ) {
    395 			ldap_unbind( ld );
    396 			rc = REWRITE_ERR;
    397 			goto rc_return;
    398 		}
    399 
    400 		if ( ldap_count_entries( ld, res ) != 1 ) {
    401 			ldap_unbind( ld );
    402 			rc = REWRITE_ERR;
    403 			goto rc_return;
    404 		}
    405 
    406 		entry = ldap_first_entry( ld, res );
    407 		if ( entry == NULL ) {
    408 			ldap_msgfree( res );
    409 			ldap_unbind( ld );
    410 			rc = REWRITE_ERR;
    411 			goto rc_return;
    412 		}
    413 		if ( attrsonly == 1 ) {
    414 			val->bv_val = ldap_get_dn( ld, entry );
    415 
    416 		} else {
    417 			values = ldap_get_values( ld, entry,
    418 					lud->lud_attrs[0] );
    419 			if ( values != NULL ) {
    420 				val->bv_val = strdup( values[ 0 ] );
    421 				ldap_value_free( values );
    422 			}
    423 		}
    424 
    425 		ldap_msgfree( res );
    426 		ldap_unbind( ld );
    427 
    428 		if ( val->bv_val == NULL ) {
    429 			rc = REWRITE_ERR;
    430 			goto rc_return;
    431 		}
    432 		val->bv_len = strlen( val->bv_val );
    433 
    434 		rc = REWRITE_SUCCESS;
    435 	} break;
    436 	}
    437 
    438 rc_return:;
    439 	return rc;
    440 }
    441 
    442 int
    443 rewrite_xmap_destroy(
    444 		struct rewrite_map **pmap
    445 )
    446 {
    447 	struct rewrite_map *map;
    448 
    449 	assert( pmap != NULL );
    450 	assert( *pmap != NULL );
    451 
    452 	map = *pmap;
    453 
    454 	switch ( map->lm_type ) {
    455 	case REWRITE_MAP_XPWDMAP:
    456 #ifdef USE_REWRITE_LDAP_PVT_THREADS
    457 		--xpasswd_mutex_init;
    458 		if ( !xpasswd_mutex_init ) {
    459 			ldap_pvt_thread_mutex_destroy( &xpasswd_mutex );
    460 		}
    461 #endif /* USE_REWRITE_LDAP_PVT_THREADS */
    462 
    463 		break;
    464 
    465 	case REWRITE_MAP_XFILEMAP:
    466 #ifdef USE_REWRITE_LDAP_PVT_THREADS
    467 		ldap_pvt_thread_mutex_lock( &map->lm_mutex );
    468 #endif /* USE_REWRITE_LDAP_PVT_THREADS */
    469 
    470 		if ( map->lm_args ) {
    471 			fclose( ( FILE * )map->lm_args );
    472 			map->lm_args = NULL;
    473 		}
    474 
    475 #ifdef USE_REWRITE_LDAP_PVT_THREADS
    476 		ldap_pvt_thread_mutex_unlock( &map->lm_mutex );
    477 		ldap_pvt_thread_mutex_destroy( &map->lm_mutex );
    478 #endif /* USE_REWRITE_LDAP_PVT_THREADS */
    479 		break;
    480 
    481 	case REWRITE_MAP_XLDAPMAP:
    482 #ifdef USE_REWRITE_LDAP_PVT_THREADS
    483 		ldap_pvt_thread_mutex_lock( &map->lm_mutex );
    484 #endif /* USE_REWRITE_LDAP_PVT_THREADS */
    485 
    486 		if ( map->lm_args ) {
    487 			ldap_free_urldesc( ( LDAPURLDesc * )map->lm_args );
    488 			map->lm_args = NULL;
    489 		}
    490 
    491 #ifdef USE_REWRITE_LDAP_PVT_THREADS
    492 		ldap_pvt_thread_mutex_unlock( &map->lm_mutex );
    493 		ldap_pvt_thread_mutex_destroy( &map->lm_mutex );
    494 #endif /* USE_REWRITE_LDAP_PVT_THREADS */
    495 		break;
    496 
    497 	default:
    498 		break;
    499 
    500 	}
    501 
    502 	free( map->lm_name );
    503 	free( map );
    504 	*pmap = NULL;
    505 
    506 	return 0;
    507 }
    508 
    509