]> git.sur5r.net Git - openldap/blob - libraries/librewrite/xmap.c
Merge remote-tracking branch 'origin/mdb.master'
[openldap] / libraries / librewrite / xmap.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 2000-2014 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                 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
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                                         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
432 rc_return:;
433         return rc;
434 }
435
436 int
437 rewrite_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