]> git.sur5r.net Git - openldap/blob - servers/slapd/saslauthz.c
ITS#2846 - make veryclean
[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
452 #ifdef NEW_LOGGING
453         LDAP_LOG( TRANSPORT, DETAIL1, 
454                 "slap_sasl_match: performing internal search (base=%s, scope=%d)\n",
455                 op.o_req_ndn.bv_val, op.oq_search.rs_scope, 0 );
456 #else
457         Debug( LDAP_DEBUG_TRACE,
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 #endif
461
462         op.o_bd = select_backend( &op.o_req_ndn, 0, 1 );
463         if(( op.o_bd == NULL ) || ( op.o_bd->be_search == NULL)) {
464                 rc = LDAP_INAPPROPRIATE_AUTH;
465                 goto CONCLUDED;
466         }
467
468         sm.dn = assertDN;
469         sm.match = 0;
470         cb.sc_private = &sm;
471
472         op.o_tag = LDAP_REQ_SEARCH;
473         op.o_protocol = LDAP_VERSION3;
474         op.o_ndn = *authc;
475         op.o_callback = &cb;
476         op.o_time = slap_get_time();
477         op.o_do_not_cache = 1;
478         op.o_is_auth_check = 1;
479         op.o_threadctx = opx->o_threadctx;
480         op.o_tmpmemctx = opx->o_tmpmemctx;
481         op.o_tmpmfuncs = opx->o_tmpmfuncs;
482 #ifdef LDAP_SLAPI
483         op.o_pb = opx->o_pb;
484 #endif
485         op.o_conn = opx->o_conn;
486         op.o_connid = opx->o_connid;
487         op.o_req_dn = op.o_req_ndn;
488
489         op.o_bd->be_search( &op, &rs );
490
491         if (sm.match) {
492                 rc = LDAP_SUCCESS;
493         } else {
494                 rc = LDAP_INAPPROPRIATE_AUTH;
495         }
496
497 CONCLUDED:
498         if( op.o_req_dn.bv_len ) ch_free( op.o_req_dn.bv_val );
499         if( op.o_req_ndn.bv_len ) sl_free( op.o_req_ndn.bv_val, opx->o_tmpmemctx );
500         if( op.oq_search.rs_filter ) filter_free_x( opx, op.oq_search.rs_filter );
501         if( op.ors_filterstr.bv_len ) ch_free( op.ors_filterstr.bv_val );
502
503 #ifdef NEW_LOGGING
504         LDAP_LOG( TRANSPORT, ENTRY, 
505                 "slap_sasl_match: comparison returned %d\n", rc, 0, 0 );
506 #else
507         Debug( LDAP_DEBUG_TRACE,
508            "<===slap_sasl_match: comparison returned %d\n", rc, 0, 0);
509 #endif
510
511         return( rc );
512 }
513
514
515 /*
516  * This function answers the question, "Can this ID authorize to that ID?",
517  * based on authorization rules. The rules are stored in the *searchDN, in the
518  * attribute named by *attr. If any of those rules map to the *assertDN, the
519  * authorization is approved.
520  *
521  * The DNs should not have the dn: prefix
522  */
523 static int
524 slap_sasl_check_authz( Operation *op,
525         struct berval *searchDN,
526         struct berval *assertDN,
527         AttributeDescription *ad,
528         struct berval *authc )
529 {
530         int i, rc;
531         BerVarray vals=NULL;
532
533 #ifdef NEW_LOGGING
534         LDAP_LOG( TRANSPORT, ENTRY, 
535                 "slap_sasl_check_authz: does %s match %s rule in %s?\n",
536             assertDN->bv_val, ad->ad_cname.bv_val, searchDN->bv_val);
537 #else
538         Debug( LDAP_DEBUG_TRACE,
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 #endif
542
543         rc = backend_attribute( op, NULL,
544                 searchDN, ad, &vals );
545         if( rc != LDAP_SUCCESS ) goto COMPLETE;
546
547         /* Check if the *assertDN matches any **vals */
548         if( vals != NULL ) {
549                 for( i=0; vals[i].bv_val != NULL; i++ ) {
550                         rc = slap_sasl_match( op, &vals[i], assertDN, authc );
551                         if ( rc == LDAP_SUCCESS ) goto COMPLETE;
552                 }
553         }
554         rc = LDAP_INAPPROPRIATE_AUTH;
555
556 COMPLETE:
557         if( vals ) ber_bvarray_free_x( vals, op->o_tmpmemctx );
558
559 #ifdef NEW_LOGGING
560         LDAP_LOG( TRANSPORT, RESULTS, 
561                 "slap_sasl_check_authz: %s check returning %s\n", 
562                 ad->ad_cname.bv_val, rc, 0 );
563 #else
564         Debug( LDAP_DEBUG_TRACE,
565            "<==slap_sasl_check_authz: %s check returning %d\n",
566                 ad->ad_cname.bv_val, rc, 0);
567 #endif
568
569         return( rc );
570 }
571
572 /*
573  * Given a SASL name (e.g. "UID=name,cn=REALM,cn=MECH,cn=AUTH")
574  * return the LDAP DN to which it matches. The SASL regexp rules in the config
575  * file turn the SASL name into an LDAP URI. If the URI is just a DN (or a
576  * search with scope=base), just return the URI (or its searchbase). Otherwise
577  * an internal search must be done, and if that search returns exactly one
578  * entry, return the DN of that one entry.
579  */
580 void slap_sasl2dn( Operation *opx,
581         struct berval *saslname, struct berval *sasldn )
582 {
583         int rc;
584         slap_callback cb = { sasl_sc_sasl2dn, NULL };
585         Operation op = {0};
586         SlapReply rs = {REP_RESULT};
587         struct berval regout = { 0, NULL };
588
589 #ifdef NEW_LOGGING
590         LDAP_LOG( TRANSPORT, ENTRY, 
591                 "slap_sasl2dn: converting SASL name %s to DN.\n",
592                 saslname->bv_val, 0, 0 );
593 #else
594         Debug( LDAP_DEBUG_TRACE, "==>slap_sasl2dn: "
595                 "converting SASL name %s to a DN\n",
596                 saslname->bv_val, 0,0 );
597 #endif
598
599         sasldn->bv_val = NULL;
600         sasldn->bv_len = 0;
601         cb.sc_private = sasldn;
602
603         /* Convert the SASL name into a minimal URI */
604         if( !slap_sasl_regexp( saslname, &regout, opx->o_tmpmemctx ) ) {
605                 goto FINISHED;
606         }
607
608         rc = slap_parseURI( opx, &regout, &op.o_req_dn,
609                 &op.o_req_ndn, &op.oq_search.rs_scope, &op.oq_search.rs_filter,
610                 &op.ors_filterstr );
611         if( regout.bv_val ) sl_free( regout.bv_val, opx->o_tmpmemctx );
612         if( rc != LDAP_SUCCESS ) {
613                 goto FINISHED;
614         }
615
616         /* Must do an internal search */
617         op.o_bd = select_backend( &op.o_req_ndn, 0, 1 );
618
619         /* Massive shortcut: search scope == base */
620         if( op.oq_search.rs_scope == LDAP_SCOPE_BASE ) {
621                 *sasldn = op.o_req_ndn;
622                 op.o_req_ndn.bv_len = 0;
623                 op.o_req_ndn.bv_val = NULL;
624                 goto FINISHED;
625         }
626
627 #ifdef NEW_LOGGING
628         LDAP_LOG( TRANSPORT, DETAIL1, 
629                 "slap_sasl2dn: performing internal search (base=%s, scope=%d)\n",
630                 op.o_req_ndn.bv_val, op.oq_search.rs_scope, 0 );
631 #else
632         Debug( LDAP_DEBUG_TRACE,
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 #endif
636
637         if(( op.o_bd == NULL ) || ( op.o_bd->be_search == NULL)) {
638                 goto FINISHED;
639         }
640
641         op.o_conn = opx->o_conn;
642         op.o_connid = opx->o_connid;
643         op.o_tag = LDAP_REQ_SEARCH;
644         op.o_protocol = LDAP_VERSION3;
645         op.o_ndn = opx->o_conn->c_ndn;
646         op.o_callback = &cb;
647         op.o_time = slap_get_time();
648         op.o_do_not_cache = 1;
649         op.o_is_auth_check = 1;
650         op.o_threadctx = opx->o_threadctx;
651         op.o_tmpmemctx = opx->o_tmpmemctx;
652         op.o_tmpmfuncs = opx->o_tmpmfuncs;
653 #ifdef LDAP_SLAPI
654         op.o_pb = opx->o_pb;
655 #endif
656         op.oq_search.rs_deref = LDAP_DEREF_NEVER;
657         op.oq_search.rs_slimit = 1;
658         op.oq_search.rs_attrsonly = 1;
659         op.o_req_dn = op.o_req_ndn;
660
661         op.o_bd->be_search( &op, &rs );
662         
663 FINISHED:
664         if( sasldn->bv_len ) {
665                 opx->o_conn->c_authz_backend = op.o_bd;
666         }
667         if( op.o_req_dn.bv_len ) ch_free( op.o_req_dn.bv_val );
668         if( op.o_req_ndn.bv_len ) sl_free( op.o_req_ndn.bv_val, opx->o_tmpmemctx );
669         if( op.oq_search.rs_filter ) filter_free_x( opx, op.oq_search.rs_filter );
670         if( op.ors_filterstr.bv_len ) ch_free( op.ors_filterstr.bv_val );
671
672 #ifdef NEW_LOGGING
673         LDAP_LOG( TRANSPORT, ENTRY, 
674                 "slap_sasl2dn: Converted SASL name to %s\n",
675                 sasldn->bv_len ? sasldn->bv_val : "<nothing>", 0, 0 );
676 #else
677         Debug( LDAP_DEBUG_TRACE, "<==slap_sasl2dn: Converted SASL name to %s\n",
678                 sasldn->bv_len ? sasldn->bv_val : "<nothing>", 0, 0 );
679 #endif
680
681         return;
682 }
683
684
685 /* Check if a bind can SASL authorize to another identity.
686  * The DNs should not have the dn: prefix
687  */
688
689 int slap_sasl_authorized( Operation *op,
690         struct berval *authcDN, struct berval *authzDN )
691 {
692         int rc = LDAP_INAPPROPRIATE_AUTH;
693
694         /* User binding as anonymous */
695         if ( authzDN == NULL ) {
696                 rc = LDAP_SUCCESS;
697                 goto DONE;
698         }
699
700 #ifdef NEW_LOGGING
701         LDAP_LOG( TRANSPORT, ENTRY, 
702                 "slap_sasl_authorized: can %s become %s?\n", 
703                 authcDN->bv_val, authzDN->bv_val, 0 );
704 #else
705         Debug( LDAP_DEBUG_TRACE,
706            "==>slap_sasl_authorized: can %s become %s?\n",
707                 authcDN->bv_val, authzDN->bv_val, 0 );
708 #endif
709
710         /* If person is authorizing to self, succeed */
711         if ( dn_match( authcDN, authzDN ) ) {
712                 rc = LDAP_SUCCESS;
713                 goto DONE;
714         }
715
716         /* Allow the manager to authorize as any DN. */
717         if( op->o_conn->c_authz_backend && be_isroot( op->o_conn->c_authz_backend, authcDN )) {
718                 rc = LDAP_SUCCESS;
719                 goto DONE;
720         }
721
722         /* Check source rules */
723         if( authz_policy & SASL_AUTHZ_TO ) {
724                 rc = slap_sasl_check_authz( op, authcDN, authzDN,
725                         slap_schema.si_ad_saslAuthzTo, authcDN );
726                 if( rc == LDAP_SUCCESS ) {
727                         goto DONE;
728                 }
729         }
730
731         /* Check destination rules */
732         if( authz_policy & SASL_AUTHZ_FROM ) {
733                 rc = slap_sasl_check_authz( op, authzDN, authcDN,
734                         slap_schema.si_ad_saslAuthzFrom, authcDN );
735                 if( rc == LDAP_SUCCESS ) {
736                         goto DONE;
737                 }
738         }
739
740         rc = LDAP_INAPPROPRIATE_AUTH;
741
742 DONE:
743
744 #ifdef NEW_LOGGING
745         LDAP_LOG( TRANSPORT, RESULTS, "slap_sasl_authorized: return %d\n", rc,0,0 );
746 #else
747         Debug( LDAP_DEBUG_TRACE,
748                 "<== slap_sasl_authorized: return %d\n", rc, 0, 0 );
749 #endif
750
751         return( rc );
752 }