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