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