xref: /netbsd-src/external/bsd/openldap/dist/libraries/librewrite/xmap.c (revision 549b59ed3ccf0d36d3097190a0db27b770f3a839)
1 /*	$NetBSD: xmap.c,v 1.3 2021/08/14 16:14:58 christos Exp $	*/
2 
3 /* $OpenLDAP$ */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5  *
6  * Copyright 2000-2021 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 *
rewrite_xmap_parse(struct rewrite_info * info,const char * s,const char ** currpos)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
rewrite_xmap_apply(struct rewrite_info * info,struct rewrite_op * op,struct rewrite_map * map,struct berval * key,struct berval * val)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
rewrite_xmap_destroy(struct rewrite_map ** pmap)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