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