]> git.sur5r.net Git - openldap/blob - servers/slapd/saslauthz.c
ITS#2764, #2781 revert backend.c patch, just catch the NULL referral
[openldap] / servers / slapd / saslauthz.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1998-2003 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 /* Portions Copyright (c) 2000, Mark Adamson, Carnegie Mellon.
16  * All rights reserved.
17  * This software is not subject to any license of Carnegie Mellon University.
18  *
19  * Redistribution and use in source and binary forms are permitted without 
20  * restriction or fee of any kind as long as this notice is preserved.
21  *
22  * The name "Carnegie Mellon" must not be used to endorse or promote
23  * products derived from this software without prior written permission.
24  */
25
26 #include "portable.h"
27
28 #include <stdio.h>
29
30 #include <ac/stdlib.h>
31 #include <ac/string.h>
32
33 #include "slap.h"
34
35 #include <limits.h>
36
37 #include <ldap_pvt.h>
38
39 #define SASLREGEX_REPLACE 10
40
41 typedef struct sasl_regexp {
42   char *sr_match;                                                       /* regexp match pattern */
43   char *sr_replace;                                             /* regexp replace pattern */
44   regex_t sr_workspace;                                         /* workspace for regexp engine */
45   int sr_offset[SASLREGEX_REPLACE+2];           /* offsets of $1,$2... in *replace */
46 } SaslRegexp_t;
47
48 static int nSaslRegexp = 0;
49 static SaslRegexp_t *SaslRegexp = NULL;
50
51 /* What SASL proxy authorization policies are allowed? */
52 #define SASL_AUTHZ_NONE 0
53 #define SASL_AUTHZ_FROM 1
54 #define SASL_AUTHZ_TO   2
55
56 static int authz_policy = SASL_AUTHZ_NONE;
57
58 int slap_sasl_setpolicy( const char *arg )
59 {
60         int rc = LDAP_SUCCESS;
61
62         if ( strcasecmp( arg, "none" ) == 0 ) {
63                 authz_policy = SASL_AUTHZ_NONE;
64         } else if ( strcasecmp( arg, "from" ) == 0 ) {
65                 authz_policy = SASL_AUTHZ_FROM;
66         } else if ( strcasecmp( arg, "to" ) == 0 ) {
67                 authz_policy = SASL_AUTHZ_TO;
68         } else if ( strcasecmp( arg, "both" ) == 0 ) {
69                 authz_policy = SASL_AUTHZ_FROM | SASL_AUTHZ_TO;
70         } else {
71                 rc = LDAP_OTHER;
72         }
73         return rc;
74 }
75
76 static int slap_parseURI( Operation *op, struct berval *uri,
77         struct berval *base, struct berval *nbase,
78         int *scope, Filter **filter, struct berval *fstr )
79 {
80         struct berval bv;
81         int rc;
82         LDAPURLDesc *ludp;
83
84         assert( uri != NULL && uri->bv_val != NULL );
85         base->bv_val = NULL;
86         base->bv_len = 0;
87         nbase->bv_val = NULL;
88         nbase->bv_len = 0;
89         fstr->bv_val = NULL;
90         fstr->bv_len = 0;
91         *scope = -1;
92         *filter = NULL;
93
94 #ifdef NEW_LOGGING
95         LDAP_LOG( TRANSPORT, ENTRY, 
96                 "slap_parseURI: parsing %s\n", uri->bv_val, 0, 0 );
97 #else
98         Debug( LDAP_DEBUG_TRACE,
99                 "slap_parseURI: parsing %s\n", uri->bv_val, 0, 0 );
100 #endif
101
102         /* If it does not look like a URI, assume it is a DN */
103         if( !strncasecmp( uri->bv_val, "dn:", sizeof("dn:")-1 ) ) {
104                 bv.bv_val = uri->bv_val + sizeof("dn:")-1;
105                 bv.bv_val += strspn( bv.bv_val, " " );
106
107 is_dn:  bv.bv_len = uri->bv_len - (bv.bv_val - uri->bv_val);
108
109                 rc = dnNormalize( 0, NULL, NULL, &bv, nbase, op->o_tmpmemctx );
110                 if( rc == LDAP_SUCCESS ) {
111                         *scope = LDAP_SCOPE_BASE;
112                 }
113                 return( rc );
114         }
115
116         rc = ldap_url_parse( uri->bv_val, &ludp );
117         if ( rc == LDAP_URL_ERR_BADSCHEME ) {
118                 bv.bv_val = uri->bv_val;
119                 goto is_dn;
120         }
121
122         if ( rc != LDAP_URL_SUCCESS ) {
123                 return LDAP_PROTOCOL_ERROR;
124         }
125
126         if (( ludp->lud_host && *ludp->lud_host )
127                 || ludp->lud_attrs || ludp->lud_exts )
128         {
129                 /* host part must be empty */
130                 /* attrs and extensions parts must be empty */
131                 rc =  LDAP_PROTOCOL_ERROR;
132                 goto done;
133         }
134
135         /* Grab the scope */
136         *scope = ludp->lud_scope;
137
138         /* Grab the filter */
139         if ( ludp->lud_filter ) {
140                 *filter = str2filter_x( op, ludp->lud_filter );
141                 if ( *filter == NULL ) {
142                         rc = LDAP_PROTOCOL_ERROR;
143                         goto done;
144                 }
145                 ber_str2bv( ludp->lud_filter, 0, 0, fstr );
146         }
147
148         /* Grab the searchbase */
149         ber_str2bv( ludp->lud_dn, 0, 0, base );
150         rc = dnNormalize( 0, NULL, NULL, base, nbase, op->o_tmpmemctx );
151
152 done:
153         if( rc != LDAP_SUCCESS ) {
154                 if( *filter ) filter_free_x( op, *filter );
155                 base->bv_val = NULL;
156                 base->bv_len = 0;
157                 fstr->bv_val = NULL;
158                 fstr->bv_len = 0;
159         } else {
160                 /* Don't free these, return them to caller */
161                 ludp->lud_filter = NULL;
162                 ludp->lud_dn= NULL;
163         }
164
165         ldap_free_urldesc( ludp );
166         return( rc );
167 }
168
169 static int slap_sasl_rx_off(char *rep, int *off)
170 {
171         const char *c;
172         int n;
173
174         /* Precompile replace pattern. Find the $<n> placeholders */
175         off[0] = -2;
176         n = 1;
177         for ( c = rep;   *c;  c++ ) {
178                 if ( *c == '\\' && c[1] ) {
179                         c++;
180                         continue;
181                 }
182                 if ( *c == '$' ) {
183                         if ( n == SASLREGEX_REPLACE ) {
184 #ifdef NEW_LOGGING
185                                 LDAP_LOG( TRANSPORT, ERR, 
186                                         "slap_sasl_rx_off: \"%s\" has too many $n "
187                                         "placeholders (max %d)\n", rep, SASLREGEX_REPLACE, 0  );
188 #else
189                                 Debug( LDAP_DEBUG_ANY,
190                                         "SASL replace pattern %s has too many $n "
191                                                 "placeholders (max %d)\n",
192                                         rep, SASLREGEX_REPLACE, 0 );
193 #endif
194
195                                 return( LDAP_OTHER );
196                         }
197                         off[n] = c - rep;
198                         n++;
199                 }
200         }
201
202         /* Final placeholder, after the last $n */
203         off[n] = c - rep;
204         n++;
205         off[n] = -1;
206         return( LDAP_SUCCESS );
207 }
208
209 int slap_sasl_regexp_config( const char *match, const char *replace )
210 {
211         int rc;
212         SaslRegexp_t *reg;
213
214         SaslRegexp = (SaslRegexp_t *) ch_realloc( (char *) SaslRegexp,
215           (nSaslRegexp + 1) * sizeof(SaslRegexp_t) );
216
217         reg = &SaslRegexp[nSaslRegexp];
218
219         reg->sr_match = ch_strdup( match );
220         reg->sr_replace = ch_strdup( replace );
221
222         /* Precompile matching pattern */
223         rc = regcomp( &reg->sr_workspace, reg->sr_match, REG_EXTENDED|REG_ICASE );
224         if ( rc ) {
225 #ifdef NEW_LOGGING
226                 LDAP_LOG( TRANSPORT, ERR, 
227                         "slap_sasl_regexp_config: \"%s\" could not be compiled.\n",
228                         reg->sr_match, 0, 0 );
229 #else
230                 Debug( LDAP_DEBUG_ANY,
231                 "SASL match pattern %s could not be compiled by regexp engine\n",
232                 reg->sr_match, 0, 0 );
233 #endif
234
235                 return( LDAP_OTHER );
236         }
237
238         rc = slap_sasl_rx_off( reg->sr_replace, reg->sr_offset );
239         if ( rc != LDAP_SUCCESS ) return rc;
240
241         nSaslRegexp++;
242         return( LDAP_SUCCESS );
243 }
244
245
246 /* Perform replacement on regexp matches */
247 static void slap_sasl_rx_exp(
248         const char *rep,
249         const int *off,
250         regmatch_t *str,
251         const char *saslname,
252         struct berval *out,
253         void *ctx )
254 {
255         int i, n, len, insert;
256
257         /* Get the total length of the final URI */
258
259         n=1;
260         len = 0;
261         while( off[n] >= 0 ) {
262                 /* Len of next section from replacement string (x,y,z above) */
263                 len += off[n] - off[n-1] - 2;
264                 if( off[n+1] < 0)
265                         break;
266
267                 /* Len of string from saslname that matched next $i  (b,d above) */
268                 i = rep[ off[n] + 1 ]   - '0';
269                 len += str[i].rm_eo - str[i].rm_so;
270                 n++;
271         }
272         out->bv_val = sl_malloc( len + 1, ctx );
273         out->bv_len = len;
274
275         /* Fill in URI with replace string, replacing $i as we go */
276         n=1;
277         insert = 0;
278         while( off[n] >= 0) {
279                 /* Paste in next section from replacement string (x,y,z above) */
280                 len = off[n] - off[n-1] - 2;
281                 strncpy( out->bv_val+insert, rep + off[n-1] + 2, len);
282                 insert += len;
283                 if( off[n+1] < 0)
284                         break;
285
286                 /* Paste in string from saslname that matched next $i  (b,d above) */
287                 i = rep[ off[n] + 1 ]   - '0';
288                 len = str[i].rm_eo - str[i].rm_so;
289                 strncpy( out->bv_val+insert, saslname + str[i].rm_so, len );
290                 insert += len;
291
292                 n++;
293         }
294
295         out->bv_val[insert] = '\0';
296 }
297
298 /* Take the passed in SASL name and attempt to convert it into an
299    LDAP URI to find the matching LDAP entry, using the pattern matching
300    strings given in the saslregexp config file directive(s) */
301
302 static int slap_sasl_regexp( struct berval *in, struct berval *out, void *ctx )
303 {
304         char *saslname = in->bv_val;
305         SaslRegexp_t *reg;
306         regmatch_t sr_strings[SASLREGEX_REPLACE];       /* strings matching $1,$2 ... */
307         int i;
308
309         memset( out, 0, sizeof( *out ) );
310
311 #ifdef NEW_LOGGING
312         LDAP_LOG( TRANSPORT, ENTRY, 
313                 "slap_sasl_regexp: converting SASL name %s\n", saslname, 0, 0 );
314 #else
315         Debug( LDAP_DEBUG_TRACE, "slap_sasl_regexp: converting SASL name %s\n",
316            saslname, 0, 0 );
317 #endif
318
319         if (( saslname == NULL ) || ( nSaslRegexp == 0 )) {
320                 return( 0 );
321         }
322
323         /* Match the normalized SASL name to the saslregexp patterns */
324         for( reg = SaslRegexp,i=0;  i<nSaslRegexp;  i++,reg++ ) {
325                 if ( regexec( &reg->sr_workspace, saslname, SASLREGEX_REPLACE,
326                   sr_strings, 0)  == 0 )
327                         break;
328         }
329
330         if( i >= nSaslRegexp ) return( 0 );
331
332         /*
333          * The match pattern may have been of the form "a(b.*)c(d.*)e" and the
334          * replace pattern of the form "x$1y$2z". The returned string needs
335          * to replace the $1,$2 with the strings that matched (b.*) and (d.*)
336          */
337         slap_sasl_rx_exp( reg->sr_replace, reg->sr_offset,
338                 sr_strings, saslname, out, ctx );
339
340 #ifdef NEW_LOGGING
341         LDAP_LOG( TRANSPORT, ENTRY, 
342                 "slap_sasl_regexp: converted SASL name to %s\n",
343                 out->bv_len ? out->bv_val : "", 0, 0 );
344 #else
345         Debug( LDAP_DEBUG_TRACE,
346                 "slap_sasl_regexp: converted SASL name to %s\n",
347                 out->bv_len ? out->bv_val : "", 0, 0 );
348 #endif
349
350         return( 1 );
351 }
352
353 /* This callback actually does some work...*/
354 static int sasl_sc_sasl2dn( Operation *o, SlapReply *rs )
355 {
356         struct berval *ndn = o->o_callback->sc_private;
357
358         if (rs->sr_type != REP_SEARCH) return 0;
359
360         /* We only want to be called once */
361         if( ndn->bv_val ) {
362                 o->o_tmpfree(ndn->bv_val, o->o_tmpmemctx);
363                 ndn->bv_val = NULL;
364
365 #ifdef NEW_LOGGING
366                 LDAP_LOG( TRANSPORT, DETAIL1,
367                         "slap_sasl2dn: search DN returned more than 1 entry\n", 0, 0, 0 );
368 #else
369                 Debug( LDAP_DEBUG_TRACE,
370                         "slap_sasl2dn: search DN returned more than 1 entry\n", 0,0,0 );
371 #endif
372                 return -1;
373         }
374
375         ber_dupbv_x(ndn, &rs->sr_entry->e_nname, o->o_tmpmemctx);
376         return 0;
377 }
378
379
380 typedef struct smatch_info {
381         struct berval *dn;
382         int match;
383 } smatch_info;
384
385 static int sasl_sc_smatch( Operation *o, SlapReply *rs )
386 {
387         smatch_info *sm = o->o_callback->sc_private;
388
389         if (rs->sr_type != REP_SEARCH) return 0;
390
391         if (dn_match(sm->dn, &rs->sr_entry->e_nname)) {
392                 sm->match = 1;
393                 return -1;      /* short-circuit the search */
394         }
395
396         return 1;
397 }
398
399 /*
400  * Map a SASL regexp rule to a DN. If the rule is just a DN or a scope=base
401  * URI, just strcmp the rule (or its searchbase) to the *assertDN. Otherwise,
402  * the rule must be used as an internal search for entries. If that search
403  * returns the *assertDN entry, the match is successful.
404  *
405  * The assertDN should not have the dn: prefix
406  */
407
408 static
409 int slap_sasl_match( Operation *opx, struct berval *rule,
410         struct berval *assertDN, struct berval *authc )
411 {
412         int rc; 
413         regex_t reg;
414         smatch_info sm;
415         slap_callback cb = { sasl_sc_smatch, NULL };
416         Operation op = {0};
417         SlapReply rs = {REP_RESULT};
418
419 #ifdef NEW_LOGGING
420         LDAP_LOG( TRANSPORT, ENTRY, 
421                 "slap_sasl_match: comparing DN %s to rule %s\n", 
422                 assertDN->bv_val, rule->bv_val,0 );
423 #else
424         Debug( LDAP_DEBUG_TRACE,
425            "===>slap_sasl_match: comparing DN %s to rule %s\n",
426                 assertDN->bv_val, rule->bv_val, 0 );
427 #endif
428
429         rc = slap_parseURI( opx, rule, &op.o_req_dn,
430                 &op.o_req_ndn, &op.oq_search.rs_scope, &op.oq_search.rs_filter,
431                 &op.ors_filterstr );
432         if( rc != LDAP_SUCCESS ) goto CONCLUDED;
433
434         /* Massive shortcut: search scope == base */
435         if( op.oq_search.rs_scope == LDAP_SCOPE_BASE ) {
436                 rc = regcomp(&reg, op.o_req_ndn.bv_val,
437                         REG_EXTENDED|REG_ICASE|REG_NOSUB);
438                 if ( rc == 0 ) {
439                         rc = regexec(&reg, assertDN->bv_val, 0, NULL, 0);
440                         regfree( &reg );
441                 }
442                 if ( rc == 0 ) {
443                         rc = LDAP_SUCCESS;
444                 } else {
445                         rc = LDAP_INAPPROPRIATE_AUTH;
446                 }
447                 goto CONCLUDED;
448         }
449
450         /* Must run an internal search. */
451         if ( op.oq_search.rs_filter == NULL ) {
452                 rc = LDAP_FILTER_ERROR;
453                 goto CONCLUDED;
454         }
455
456 #ifdef NEW_LOGGING
457         LDAP_LOG( TRANSPORT, DETAIL1, 
458                 "slap_sasl_match: performing internal search (base=%s, scope=%d)\n",
459                 op.o_req_ndn.bv_val, op.oq_search.rs_scope, 0 );
460 #else
461         Debug( LDAP_DEBUG_TRACE,
462            "slap_sasl_match: performing internal search (base=%s, scope=%d)\n",
463            op.o_req_ndn.bv_val, op.oq_search.rs_scope, 0 );
464 #endif
465
466         op.o_bd = select_backend( &op.o_req_ndn, 0, 1 );
467         if(( op.o_bd == NULL ) || ( op.o_bd->be_search == NULL)) {
468                 rc = LDAP_INAPPROPRIATE_AUTH;
469                 goto CONCLUDED;
470         }
471
472         sm.dn = assertDN;
473         sm.match = 0;
474         cb.sc_private = &sm;
475
476         op.o_tag = LDAP_REQ_SEARCH;
477         op.o_protocol = LDAP_VERSION3;
478         op.o_ndn = *authc;
479         op.o_callback = &cb;
480         op.o_time = slap_get_time();
481         op.o_do_not_cache = 1;
482         op.o_is_auth_check = 1;
483         op.o_threadctx = opx->o_threadctx;
484         op.o_tmpmemctx = opx->o_tmpmemctx;
485         op.o_tmpmfuncs = opx->o_tmpmfuncs;
486 #ifdef LDAP_SLAPI
487         op.o_pb = opx->o_pb;
488 #endif
489         op.o_conn = opx->o_conn;
490         op.o_connid = opx->o_connid;
491         op.o_req_dn = op.o_req_ndn;
492
493         op.o_bd->be_search( &op, &rs );
494
495         if (sm.match) {
496                 rc = LDAP_SUCCESS;
497         } else {
498                 rc = LDAP_INAPPROPRIATE_AUTH;
499         }
500
501 CONCLUDED:
502         if( op.o_req_dn.bv_len ) ch_free( op.o_req_dn.bv_val );
503         if( op.o_req_ndn.bv_len ) sl_free( op.o_req_ndn.bv_val, opx->o_tmpmemctx );
504         if( op.oq_search.rs_filter ) filter_free_x( opx, op.oq_search.rs_filter );
505         if( op.ors_filterstr.bv_len ) ch_free( op.ors_filterstr.bv_val );
506
507 #ifdef NEW_LOGGING
508         LDAP_LOG( TRANSPORT, ENTRY, 
509                 "slap_sasl_match: comparison returned %d\n", rc, 0, 0 );
510 #else
511         Debug( LDAP_DEBUG_TRACE,
512            "<===slap_sasl_match: comparison returned %d\n", rc, 0, 0);
513 #endif
514
515         return( rc );
516 }
517
518
519 /*
520  * This function answers the question, "Can this ID authorize to that ID?",
521  * based on authorization rules. The rules are stored in the *searchDN, in the
522  * attribute named by *attr. If any of those rules map to the *assertDN, the
523  * authorization is approved.
524  *
525  * The DNs should not have the dn: prefix
526  */
527 static int
528 slap_sasl_check_authz( Operation *op,
529         struct berval *searchDN,
530         struct berval *assertDN,
531         AttributeDescription *ad,
532         struct berval *authc )
533 {
534         int i, rc;
535         BerVarray vals=NULL;
536
537 #ifdef NEW_LOGGING
538         LDAP_LOG( TRANSPORT, ENTRY, 
539                 "slap_sasl_check_authz: does %s match %s rule in %s?\n",
540             assertDN->bv_val, ad->ad_cname.bv_val, searchDN->bv_val);
541 #else
542         Debug( LDAP_DEBUG_TRACE,
543            "==>slap_sasl_check_authz: does %s match %s rule in %s?\n",
544            assertDN->bv_val, ad->ad_cname.bv_val, searchDN->bv_val);
545 #endif
546
547         rc = backend_attribute( op, NULL,
548                 searchDN, ad, &vals );
549         if( rc != LDAP_SUCCESS ) goto COMPLETE;
550
551         /* Check if the *assertDN matches any **vals */
552         if( vals != NULL ) {
553                 for( i=0; vals[i].bv_val != NULL; i++ ) {
554                         rc = slap_sasl_match( op, &vals[i], assertDN, authc );
555                         if ( rc == LDAP_SUCCESS ) goto COMPLETE;
556                 }
557         }
558         rc = LDAP_INAPPROPRIATE_AUTH;
559
560 COMPLETE:
561         if( vals ) ber_bvarray_free_x( vals, op->o_tmpmemctx );
562
563 #ifdef NEW_LOGGING
564         LDAP_LOG( TRANSPORT, RESULTS, 
565                 "slap_sasl_check_authz: %s check returning %s\n", 
566                 ad->ad_cname.bv_val, rc, 0 );
567 #else
568         Debug( LDAP_DEBUG_TRACE,
569            "<==slap_sasl_check_authz: %s check returning %d\n",
570                 ad->ad_cname.bv_val, rc, 0);
571 #endif
572
573         return( rc );
574 }
575
576 /*
577  * Given a SASL name (e.g. "UID=name,cn=REALM,cn=MECH,cn=AUTH")
578  * return the LDAP DN to which it matches. The SASL regexp rules in the config
579  * file turn the SASL name into an LDAP URI. If the URI is just a DN (or a
580  * search with scope=base), just return the URI (or its searchbase). Otherwise
581  * an internal search must be done, and if that search returns exactly one
582  * entry, return the DN of that one entry.
583  */
584 void slap_sasl2dn( Operation *opx,
585         struct berval *saslname, struct berval *sasldn )
586 {
587         int rc;
588         slap_callback cb = { sasl_sc_sasl2dn, NULL };
589         Operation op = {0};
590         SlapReply rs = {REP_RESULT};
591         struct berval regout = { 0, NULL };
592
593 #ifdef NEW_LOGGING
594         LDAP_LOG( TRANSPORT, ENTRY, 
595                 "slap_sasl2dn: converting SASL name %s to DN.\n",
596                 saslname->bv_val, 0, 0 );
597 #else
598         Debug( LDAP_DEBUG_TRACE, "==>slap_sasl2dn: "
599                 "converting SASL name %s to a DN\n",
600                 saslname->bv_val, 0,0 );
601 #endif
602
603         sasldn->bv_val = NULL;
604         sasldn->bv_len = 0;
605         cb.sc_private = sasldn;
606
607         /* Convert the SASL name into a minimal URI */
608         if( !slap_sasl_regexp( saslname, &regout, opx->o_tmpmemctx ) ) {
609                 goto FINISHED;
610         }
611
612         rc = slap_parseURI( opx, &regout, &op.o_req_dn,
613                 &op.o_req_ndn, &op.oq_search.rs_scope, &op.oq_search.rs_filter,
614                 &op.ors_filterstr );
615         if( regout.bv_val ) sl_free( regout.bv_val, opx->o_tmpmemctx );
616         if( rc != LDAP_SUCCESS ) {
617                 goto FINISHED;
618         }
619
620         /* Must do an internal search */
621         op.o_bd = select_backend( &op.o_req_ndn, 0, 1 );
622
623         /* Massive shortcut: search scope == base */
624         if( op.oq_search.rs_scope == LDAP_SCOPE_BASE ) {
625                 *sasldn = op.o_req_ndn;
626                 op.o_req_ndn.bv_len = 0;
627                 op.o_req_ndn.bv_val = NULL;
628                 goto FINISHED;
629         }
630
631 #ifdef NEW_LOGGING
632         LDAP_LOG( TRANSPORT, DETAIL1, 
633                 "slap_sasl2dn: performing internal search (base=%s, scope=%d)\n",
634                 op.o_req_ndn.bv_val, op.oq_search.rs_scope, 0 );
635 #else
636         Debug( LDAP_DEBUG_TRACE,
637                 "slap_sasl2dn: performing internal search (base=%s, scope=%d)\n",
638                 op.o_req_ndn.bv_val, op.oq_search.rs_scope, 0 );
639 #endif
640
641         if(( op.o_bd == NULL ) || ( op.o_bd->be_search == NULL)) {
642                 goto FINISHED;
643         }
644
645         op.o_conn = opx->o_conn;
646         op.o_connid = opx->o_connid;
647         op.o_tag = LDAP_REQ_SEARCH;
648         op.o_protocol = LDAP_VERSION3;
649         op.o_ndn = opx->o_conn->c_ndn;
650         op.o_callback = &cb;
651         op.o_time = slap_get_time();
652         op.o_do_not_cache = 1;
653         op.o_is_auth_check = 1;
654         op.o_threadctx = opx->o_threadctx;
655         op.o_tmpmemctx = opx->o_tmpmemctx;
656         op.o_tmpmfuncs = opx->o_tmpmfuncs;
657 #ifdef LDAP_SLAPI
658         op.o_pb = opx->o_pb;
659 #endif
660         op.oq_search.rs_deref = LDAP_DEREF_NEVER;
661         op.oq_search.rs_slimit = 1;
662         op.oq_search.rs_attrsonly = 1;
663         op.o_req_dn = op.o_req_ndn;
664
665         op.o_bd->be_search( &op, &rs );
666         
667 FINISHED:
668         if( sasldn->bv_len ) {
669                 opx->o_conn->c_authz_backend = op.o_bd;
670         }
671         if( op.o_req_dn.bv_len ) ch_free( op.o_req_dn.bv_val );
672         if( op.o_req_ndn.bv_len ) sl_free( op.o_req_ndn.bv_val, opx->o_tmpmemctx );
673         if( op.oq_search.rs_filter ) filter_free_x( opx, op.oq_search.rs_filter );
674         if( op.ors_filterstr.bv_len ) ch_free( op.ors_filterstr.bv_val );
675
676 #ifdef NEW_LOGGING
677         LDAP_LOG( TRANSPORT, ENTRY, 
678                 "slap_sasl2dn: Converted SASL name to %s\n",
679                 sasldn->bv_len ? sasldn->bv_val : "<nothing>", 0, 0 );
680 #else
681         Debug( LDAP_DEBUG_TRACE, "<==slap_sasl2dn: Converted SASL name to %s\n",
682                 sasldn->bv_len ? sasldn->bv_val : "<nothing>", 0, 0 );
683 #endif
684
685         return;
686 }
687
688
689 /* Check if a bind can SASL authorize to another identity.
690  * The DNs should not have the dn: prefix
691  */
692
693 int slap_sasl_authorized( Operation *op,
694         struct berval *authcDN, struct berval *authzDN )
695 {
696         int rc = LDAP_INAPPROPRIATE_AUTH;
697
698         /* User binding as anonymous */
699         if ( authzDN == NULL ) {
700                 rc = LDAP_SUCCESS;
701                 goto DONE;
702         }
703
704 #ifdef NEW_LOGGING
705         LDAP_LOG( TRANSPORT, ENTRY, 
706                 "slap_sasl_authorized: can %s become %s?\n", 
707                 authcDN->bv_val, authzDN->bv_val, 0 );
708 #else
709         Debug( LDAP_DEBUG_TRACE,
710            "==>slap_sasl_authorized: can %s become %s?\n",
711                 authcDN->bv_val, authzDN->bv_val, 0 );
712 #endif
713
714         /* If person is authorizing to self, succeed */
715         if ( dn_match( authcDN, authzDN ) ) {
716                 rc = LDAP_SUCCESS;
717                 goto DONE;
718         }
719
720         /* Allow the manager to authorize as any DN. */
721         if( op->o_conn->c_authz_backend && be_isroot( op->o_conn->c_authz_backend, authcDN )) {
722                 rc = LDAP_SUCCESS;
723                 goto DONE;
724         }
725
726         /* Check source rules */
727         if( authz_policy & SASL_AUTHZ_TO ) {
728                 rc = slap_sasl_check_authz( op, authcDN, authzDN,
729                         slap_schema.si_ad_saslAuthzTo, authcDN );
730                 if( rc == LDAP_SUCCESS ) {
731                         goto DONE;
732                 }
733         }
734
735         /* Check destination rules */
736         if( authz_policy & SASL_AUTHZ_FROM ) {
737                 rc = slap_sasl_check_authz( op, authzDN, authcDN,
738                         slap_schema.si_ad_saslAuthzFrom, authcDN );
739                 if( rc == LDAP_SUCCESS ) {
740                         goto DONE;
741                 }
742         }
743
744         rc = LDAP_INAPPROPRIATE_AUTH;
745
746 DONE:
747
748 #ifdef NEW_LOGGING
749         LDAP_LOG( TRANSPORT, RESULTS, "slap_sasl_authorized: return %d\n", rc,0,0 );
750 #else
751         Debug( LDAP_DEBUG_TRACE,
752                 "<== slap_sasl_authorized: return %d\n", rc, 0, 0 );
753 #endif
754
755         return( rc );
756 }