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