1/* $OpenLDAP$ */
2/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3 *
4 * Copyright 2000-2011 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
36ldap_pvt_thread_mutex_t xpasswd_mutex;
37static 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 */
45struct rewrite_map *
46rewrite_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%s%s",
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%s%s%s", "", "", "" );
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 */
239int
240rewrite_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					return REWRITE_ERR;
339				}
340
341				val->bv_len = strlen( p );
342
343#ifdef USE_REWRITE_LDAP_PVT_THREADS
344				ldap_pvt_thread_mutex_unlock( &map->lm_mutex );
345#endif /* USE_REWRITE_LDAP_PVT_THREADS */
346
347				goto rc_return;
348			}
349		}
350
351#ifdef USE_REWRITE_LDAP_PVT_THREADS
352		ldap_pvt_thread_mutex_unlock( &map->lm_mutex );
353#endif /* USE_REWRITE_LDAP_PVT_THREADS */
354
355		rc = REWRITE_ERR;
356
357		break;
358	}
359
360	case REWRITE_MAP_XLDAPMAP: {
361		LDAP *ld;
362		char filter[1024];
363		LDAPMessage *res = NULL, *entry;
364		LDAPURLDesc *lud = ( LDAPURLDesc * )map->lm_args;
365		int attrsonly = 0;
366		char **values;
367
368		assert( lud != NULL );
369
370		/*
371		 * No mutex because there is no write on the map data
372		 */
373
374		ld = ldap_init( lud->lud_host, lud->lud_port );
375		if ( ld == NULL ) {
376			rc = REWRITE_ERR;
377			goto rc_return;
378		}
379
380		snprintf( filter, sizeof( filter ), lud->lud_filter,
381				key->bv_val );
382
383		if ( strcasecmp( lud->lud_attrs[ 0 ], "dn" ) == 0 ) {
384			attrsonly = 1;
385		}
386		rc = ldap_search_s( ld, lud->lud_dn, lud->lud_scope,
387				filter, lud->lud_attrs, attrsonly, &res );
388		if ( rc != LDAP_SUCCESS ) {
389			ldap_unbind( ld );
390			rc = REWRITE_ERR;
391			goto rc_return;
392		}
393
394		if ( ldap_count_entries( ld, res ) != 1 ) {
395			ldap_unbind( ld );
396			rc = REWRITE_ERR;
397			goto rc_return;
398		}
399
400		entry = ldap_first_entry( ld, res );
401		if ( entry == NULL ) {
402			ldap_msgfree( res );
403			ldap_unbind( ld );
404			rc = REWRITE_ERR;
405			goto rc_return;
406		}
407		if ( attrsonly == 1 ) {
408			val->bv_val = ldap_get_dn( ld, entry );
409
410		} else {
411			values = ldap_get_values( ld, entry,
412					lud->lud_attrs[0] );
413			if ( values != NULL ) {
414				val->bv_val = strdup( values[ 0 ] );
415				ldap_value_free( values );
416			}
417		}
418
419		ldap_msgfree( res );
420		ldap_unbind( ld );
421
422		if ( val->bv_val == NULL ) {
423			rc = REWRITE_ERR;
424			goto rc_return;
425		}
426		val->bv_len = strlen( val->bv_val );
427
428		rc = REWRITE_SUCCESS;
429	} break;
430	}
431
432rc_return:;
433	return rc;
434}
435
436int
437rewrite_xmap_destroy(
438		struct rewrite_map **pmap
439)
440{
441	struct rewrite_map *map;
442
443	assert( pmap != NULL );
444	assert( *pmap != NULL );
445
446	map = *pmap;
447
448	switch ( map->lm_type ) {
449	case REWRITE_MAP_XPWDMAP:
450#ifdef USE_REWRITE_LDAP_PVT_THREADS
451		--xpasswd_mutex_init;
452		if ( !xpasswd_mutex_init ) {
453			ldap_pvt_thread_mutex_destroy( &xpasswd_mutex );
454		}
455#endif /* USE_REWRITE_LDAP_PVT_THREADS */
456
457		break;
458
459	case REWRITE_MAP_XFILEMAP:
460#ifdef USE_REWRITE_LDAP_PVT_THREADS
461		ldap_pvt_thread_mutex_lock( &map->lm_mutex );
462#endif /* USE_REWRITE_LDAP_PVT_THREADS */
463
464		if ( map->lm_args ) {
465			fclose( ( FILE * )map->lm_args );
466			map->lm_args = NULL;
467		}
468
469#ifdef USE_REWRITE_LDAP_PVT_THREADS
470		ldap_pvt_thread_mutex_unlock( &map->lm_mutex );
471		ldap_pvt_thread_mutex_destroy( &map->lm_mutex );
472#endif /* USE_REWRITE_LDAP_PVT_THREADS */
473		break;
474
475	case REWRITE_MAP_XLDAPMAP:
476#ifdef USE_REWRITE_LDAP_PVT_THREADS
477		ldap_pvt_thread_mutex_lock( &map->lm_mutex );
478#endif /* USE_REWRITE_LDAP_PVT_THREADS */
479
480		if ( map->lm_args ) {
481			ldap_free_urldesc( ( LDAPURLDesc * )map->lm_args );
482			map->lm_args = NULL;
483		}
484
485#ifdef USE_REWRITE_LDAP_PVT_THREADS
486		ldap_pvt_thread_mutex_unlock( &map->lm_mutex );
487		ldap_pvt_thread_mutex_destroy( &map->lm_mutex );
488#endif /* USE_REWRITE_LDAP_PVT_THREADS */
489		break;
490
491	default:
492		break;
493
494	}
495
496	free( map->lm_name );
497	free( map );
498	*pmap = NULL;
499
500	return 0;
501}
502
503