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