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