saslauthz.c revision 1.1 1 1.1 lukem /* $OpenLDAP: pkg/ldap/servers/slapd/saslauthz.c,v 1.163.2.8 2008/02/11 23:26:44 kurt Exp $ */
2 1.1 lukem /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3 1.1 lukem *
4 1.1 lukem * Copyright 1998-2008 The OpenLDAP Foundation.
5 1.1 lukem * Portions Copyright 2000 Mark Adamson, Carnegie Mellon.
6 1.1 lukem * All rights reserved.
7 1.1 lukem *
8 1.1 lukem * Redistribution and use in source and binary forms, with or without
9 1.1 lukem * modification, are permitted only as authorized by the OpenLDAP
10 1.1 lukem * Public License.
11 1.1 lukem *
12 1.1 lukem * A copy of this license is available in the file LICENSE in the
13 1.1 lukem * top-level directory of the distribution or, alternatively, at
14 1.1 lukem * <http://www.OpenLDAP.org/license.html>.
15 1.1 lukem */
16 1.1 lukem
17 1.1 lukem #include "portable.h"
18 1.1 lukem
19 1.1 lukem #include <stdio.h>
20 1.1 lukem #ifdef HAVE_LIMITS_H
21 1.1 lukem #include <limits.h>
22 1.1 lukem #endif
23 1.1 lukem
24 1.1 lukem #include <ac/stdlib.h>
25 1.1 lukem #include <ac/string.h>
26 1.1 lukem #include <ac/ctype.h>
27 1.1 lukem
28 1.1 lukem #include "slap.h"
29 1.1 lukem
30 1.1 lukem #include "lutil.h"
31 1.1 lukem
32 1.1 lukem #define SASLREGEX_REPLACE 10
33 1.1 lukem
34 1.1 lukem #define LDAP_X_SCOPE_EXACT ((ber_int_t) 0x0010)
35 1.1 lukem #define LDAP_X_SCOPE_REGEX ((ber_int_t) 0x0020)
36 1.1 lukem #define LDAP_X_SCOPE_CHILDREN ((ber_int_t) 0x0030)
37 1.1 lukem #define LDAP_X_SCOPE_SUBTREE ((ber_int_t) 0x0040)
38 1.1 lukem #define LDAP_X_SCOPE_ONELEVEL ((ber_int_t) 0x0050)
39 1.1 lukem #define LDAP_X_SCOPE_GROUP ((ber_int_t) 0x0060)
40 1.1 lukem #define LDAP_X_SCOPE_USERS ((ber_int_t) 0x0070)
41 1.1 lukem
42 1.1 lukem /*
43 1.1 lukem * IDs in DNauthzid form can now have a type specifier, that
44 1.1 lukem * influences how they are used in related operations.
45 1.1 lukem *
46 1.1 lukem * syntax: dn[.{exact|regex}]:<val>
47 1.1 lukem *
48 1.1 lukem * dn.exact: the value must pass normalization and is used
49 1.1 lukem * in exact DN match.
50 1.1 lukem * dn.regex: the value is treated as a regular expression
51 1.1 lukem * in matching DN values in authz{To|From}
52 1.1 lukem * attributes.
53 1.1 lukem * dn: for backwards compatibility reasons, the value
54 1.1 lukem * is treated as a regular expression, and thus
55 1.1 lukem * it is not normalized nor validated; it is used
56 1.1 lukem * in exact or regex comparisons based on the
57 1.1 lukem * context.
58 1.1 lukem *
59 1.1 lukem * IDs in DNauthzid form can now have a type specifier, that
60 1.1 lukem * influences how they are used in related operations.
61 1.1 lukem *
62 1.1 lukem * syntax: u[.mech[/realm]]:<val>
63 1.1 lukem *
64 1.1 lukem * where mech is a SIMPLE, AUTHZ, or a SASL mechanism name
65 1.1 lukem * and realm is mechanism specific realm (separate to those
66 1.1 lukem * which are representable as part of the principal).
67 1.1 lukem */
68 1.1 lukem
69 1.1 lukem typedef struct sasl_regexp {
70 1.1 lukem char *sr_match; /* regexp match pattern */
71 1.1 lukem char *sr_replace; /* regexp replace pattern */
72 1.1 lukem regex_t sr_workspace; /* workspace for regexp engine */
73 1.1 lukem int sr_offset[SASLREGEX_REPLACE+2]; /* offsets of $1,$2... in *replace */
74 1.1 lukem } SaslRegexp_t;
75 1.1 lukem
76 1.1 lukem static int nSaslRegexp = 0;
77 1.1 lukem static SaslRegexp_t *SaslRegexp = NULL;
78 1.1 lukem
79 1.1 lukem #ifdef SLAP_AUTH_REWRITE
80 1.1 lukem #include "rewrite.h"
81 1.1 lukem struct rewrite_info *sasl_rwinfo = NULL;
82 1.1 lukem #define AUTHID_CONTEXT "authid"
83 1.1 lukem #endif /* SLAP_AUTH_REWRITE */
84 1.1 lukem
85 1.1 lukem /* What SASL proxy authorization policies are allowed? */
86 1.1 lukem #define SASL_AUTHZ_NONE 0x00
87 1.1 lukem #define SASL_AUTHZ_FROM 0x01
88 1.1 lukem #define SASL_AUTHZ_TO 0x02
89 1.1 lukem #define SASL_AUTHZ_AND 0x10
90 1.1 lukem
91 1.1 lukem static const char *policy_txt[] = {
92 1.1 lukem "none", "from", "to", "any"
93 1.1 lukem };
94 1.1 lukem
95 1.1 lukem static int authz_policy = SASL_AUTHZ_NONE;
96 1.1 lukem
97 1.1 lukem static int
98 1.1 lukem slap_sasl_match( Operation *opx, struct berval *rule,
99 1.1 lukem struct berval *assertDN, struct berval *authc );
100 1.1 lukem
101 1.1 lukem int slap_sasl_setpolicy( const char *arg )
102 1.1 lukem {
103 1.1 lukem int rc = LDAP_SUCCESS;
104 1.1 lukem
105 1.1 lukem if ( strcasecmp( arg, "none" ) == 0 ) {
106 1.1 lukem authz_policy = SASL_AUTHZ_NONE;
107 1.1 lukem } else if ( strcasecmp( arg, "from" ) == 0 ) {
108 1.1 lukem authz_policy = SASL_AUTHZ_FROM;
109 1.1 lukem } else if ( strcasecmp( arg, "to" ) == 0 ) {
110 1.1 lukem authz_policy = SASL_AUTHZ_TO;
111 1.1 lukem } else if ( strcasecmp( arg, "both" ) == 0 || strcasecmp( arg, "any" ) == 0 ) {
112 1.1 lukem authz_policy = SASL_AUTHZ_FROM | SASL_AUTHZ_TO;
113 1.1 lukem } else if ( strcasecmp( arg, "all" ) == 0 ) {
114 1.1 lukem authz_policy = SASL_AUTHZ_FROM | SASL_AUTHZ_TO | SASL_AUTHZ_AND;
115 1.1 lukem } else {
116 1.1 lukem rc = LDAP_OTHER;
117 1.1 lukem }
118 1.1 lukem return rc;
119 1.1 lukem }
120 1.1 lukem
121 1.1 lukem const char * slap_sasl_getpolicy()
122 1.1 lukem {
123 1.1 lukem if ( authz_policy == (SASL_AUTHZ_FROM | SASL_AUTHZ_TO | SASL_AUTHZ_AND) )
124 1.1 lukem return "all";
125 1.1 lukem else
126 1.1 lukem return policy_txt[authz_policy];
127 1.1 lukem }
128 1.1 lukem
129 1.1 lukem int slap_parse_user( struct berval *id, struct berval *user,
130 1.1 lukem struct berval *realm, struct berval *mech )
131 1.1 lukem {
132 1.1 lukem char u;
133 1.1 lukem
134 1.1 lukem assert( id != NULL );
135 1.1 lukem assert( !BER_BVISNULL( id ) );
136 1.1 lukem assert( user != NULL );
137 1.1 lukem assert( realm != NULL );
138 1.1 lukem assert( mech != NULL );
139 1.1 lukem
140 1.1 lukem u = id->bv_val[ 0 ];
141 1.1 lukem
142 1.1 lukem if ( u != 'u' && u != 'U' ) {
143 1.1 lukem /* called with something other than u: */
144 1.1 lukem return LDAP_PROTOCOL_ERROR;
145 1.1 lukem }
146 1.1 lukem
147 1.1 lukem /* uauthzid form:
148 1.1 lukem * u[.mech[/realm]]:user
149 1.1 lukem */
150 1.1 lukem
151 1.1 lukem user->bv_val = ber_bvchr( id, ':' );
152 1.1 lukem if ( BER_BVISNULL( user ) ) {
153 1.1 lukem return LDAP_PROTOCOL_ERROR;
154 1.1 lukem }
155 1.1 lukem user->bv_val[ 0 ] = '\0';
156 1.1 lukem user->bv_val++;
157 1.1 lukem user->bv_len = id->bv_len - ( user->bv_val - id->bv_val );
158 1.1 lukem
159 1.1 lukem mech->bv_val = ber_bvchr( id, '.' );
160 1.1 lukem if ( !BER_BVISNULL( mech ) ) {
161 1.1 lukem mech->bv_val[ 0 ] = '\0';
162 1.1 lukem mech->bv_val++;
163 1.1 lukem mech->bv_len = user->bv_val - mech->bv_val - 1;
164 1.1 lukem
165 1.1 lukem realm->bv_val = ber_bvchr( mech, '/' );
166 1.1 lukem
167 1.1 lukem if ( !BER_BVISNULL( realm ) ) {
168 1.1 lukem realm->bv_val[ 0 ] = '\0';
169 1.1 lukem realm->bv_val++;
170 1.1 lukem mech->bv_len = realm->bv_val - mech->bv_val - 1;
171 1.1 lukem realm->bv_len = user->bv_val - realm->bv_val - 1;
172 1.1 lukem }
173 1.1 lukem
174 1.1 lukem } else {
175 1.1 lukem BER_BVZERO( realm );
176 1.1 lukem }
177 1.1 lukem
178 1.1 lukem if ( id->bv_val[ 1 ] != '\0' ) {
179 1.1 lukem return LDAP_PROTOCOL_ERROR;
180 1.1 lukem }
181 1.1 lukem
182 1.1 lukem if ( !BER_BVISNULL( mech ) ) {
183 1.1 lukem assert( mech->bv_val == id->bv_val + 2 );
184 1.1 lukem
185 1.1 lukem AC_MEMCPY( mech->bv_val - 2, mech->bv_val, mech->bv_len + 1 );
186 1.1 lukem mech->bv_val -= 2;
187 1.1 lukem }
188 1.1 lukem
189 1.1 lukem if ( !BER_BVISNULL( realm ) ) {
190 1.1 lukem assert( realm->bv_val >= id->bv_val + 2 );
191 1.1 lukem
192 1.1 lukem AC_MEMCPY( realm->bv_val - 2, realm->bv_val, realm->bv_len + 1 );
193 1.1 lukem realm->bv_val -= 2;
194 1.1 lukem }
195 1.1 lukem
196 1.1 lukem /* leave "u:" before user */
197 1.1 lukem user->bv_val -= 2;
198 1.1 lukem user->bv_len += 2;
199 1.1 lukem user->bv_val[ 0 ] = u;
200 1.1 lukem user->bv_val[ 1 ] = ':';
201 1.1 lukem
202 1.1 lukem return LDAP_SUCCESS;
203 1.1 lukem }
204 1.1 lukem
205 1.1 lukem int
206 1.1 lukem authzValidate(
207 1.1 lukem Syntax *syntax,
208 1.1 lukem struct berval *in )
209 1.1 lukem {
210 1.1 lukem struct berval bv;
211 1.1 lukem int rc = LDAP_INVALID_SYNTAX;
212 1.1 lukem LDAPURLDesc *ludp = NULL;
213 1.1 lukem int scope = -1;
214 1.1 lukem
215 1.1 lukem /*
216 1.1 lukem * 1) <DN>
217 1.1 lukem * 2) dn[.{exact|children|subtree|onelevel}]:{*|<DN>}
218 1.1 lukem * 3) dn.regex:<pattern>
219 1.1 lukem * 4) u[.mech[/realm]]:<ID>
220 1.1 lukem * 5) group[/<groupClass>[/<memberAttr>]]:<DN>
221 1.1 lukem * 6) <URL>
222 1.1 lukem */
223 1.1 lukem
224 1.1 lukem assert( in != NULL );
225 1.1 lukem assert( !BER_BVISNULL( in ) );
226 1.1 lukem
227 1.1 lukem Debug( LDAP_DEBUG_TRACE,
228 1.1 lukem "authzValidate: parsing %s\n", in->bv_val, 0, 0 );
229 1.1 lukem
230 1.1 lukem /*
231 1.1 lukem * 2) dn[.{exact|children|subtree|onelevel}]:{*|<DN>}
232 1.1 lukem * 3) dn.regex:<pattern>
233 1.1 lukem *
234 1.1 lukem * <DN> must pass DN normalization
235 1.1 lukem */
236 1.1 lukem if ( !strncasecmp( in->bv_val, "dn", STRLENOF( "dn" ) ) ) {
237 1.1 lukem bv.bv_val = in->bv_val + STRLENOF( "dn" );
238 1.1 lukem
239 1.1 lukem if ( bv.bv_val[ 0 ] == '.' ) {
240 1.1 lukem bv.bv_val++;
241 1.1 lukem
242 1.1 lukem if ( !strncasecmp( bv.bv_val, "exact:", STRLENOF( "exact:" ) ) ) {
243 1.1 lukem bv.bv_val += STRLENOF( "exact:" );
244 1.1 lukem scope = LDAP_X_SCOPE_EXACT;
245 1.1 lukem
246 1.1 lukem } else if ( !strncasecmp( bv.bv_val, "regex:", STRLENOF( "regex:" ) ) ) {
247 1.1 lukem bv.bv_val += STRLENOF( "regex:" );
248 1.1 lukem scope = LDAP_X_SCOPE_REGEX;
249 1.1 lukem
250 1.1 lukem } else if ( !strncasecmp( bv.bv_val, "children:", STRLENOF( "children:" ) ) ) {
251 1.1 lukem bv.bv_val += STRLENOF( "children:" );
252 1.1 lukem scope = LDAP_X_SCOPE_CHILDREN;
253 1.1 lukem
254 1.1 lukem } else if ( !strncasecmp( bv.bv_val, "subtree:", STRLENOF( "subtree:" ) ) ) {
255 1.1 lukem bv.bv_val += STRLENOF( "subtree:" );
256 1.1 lukem scope = LDAP_X_SCOPE_SUBTREE;
257 1.1 lukem
258 1.1 lukem } else if ( !strncasecmp( bv.bv_val, "onelevel:", STRLENOF( "onelevel:" ) ) ) {
259 1.1 lukem bv.bv_val += STRLENOF( "onelevel:" );
260 1.1 lukem scope = LDAP_X_SCOPE_ONELEVEL;
261 1.1 lukem
262 1.1 lukem } else {
263 1.1 lukem return LDAP_INVALID_SYNTAX;
264 1.1 lukem }
265 1.1 lukem
266 1.1 lukem } else {
267 1.1 lukem if ( bv.bv_val[ 0 ] != ':' ) {
268 1.1 lukem return LDAP_INVALID_SYNTAX;
269 1.1 lukem }
270 1.1 lukem scope = LDAP_X_SCOPE_EXACT;
271 1.1 lukem bv.bv_val++;
272 1.1 lukem }
273 1.1 lukem
274 1.1 lukem bv.bv_val += strspn( bv.bv_val, " " );
275 1.1 lukem /* jump here in case no type specification was present
276 1.1 lukem * and uri was not an URI... HEADS-UP: assuming EXACT */
277 1.1 lukem is_dn: bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
278 1.1 lukem
279 1.1 lukem /* a single '*' means any DN without using regexes */
280 1.1 lukem if ( ber_bvccmp( &bv, '*' ) ) {
281 1.1 lukem /* LDAP_X_SCOPE_USERS */
282 1.1 lukem return LDAP_SUCCESS;
283 1.1 lukem }
284 1.1 lukem
285 1.1 lukem switch ( scope ) {
286 1.1 lukem case LDAP_X_SCOPE_EXACT:
287 1.1 lukem case LDAP_X_SCOPE_CHILDREN:
288 1.1 lukem case LDAP_X_SCOPE_SUBTREE:
289 1.1 lukem case LDAP_X_SCOPE_ONELEVEL:
290 1.1 lukem return dnValidate( NULL, &bv );
291 1.1 lukem
292 1.1 lukem case LDAP_X_SCOPE_REGEX:
293 1.1 lukem return LDAP_SUCCESS;
294 1.1 lukem }
295 1.1 lukem
296 1.1 lukem return rc;
297 1.1 lukem
298 1.1 lukem /*
299 1.1 lukem * 4) u[.mech[/realm]]:<ID>
300 1.1 lukem */
301 1.1 lukem } else if ( ( in->bv_val[ 0 ] == 'u' || in->bv_val[ 0 ] == 'U' )
302 1.1 lukem && ( in->bv_val[ 1 ] == ':'
303 1.1 lukem || in->bv_val[ 1 ] == '/'
304 1.1 lukem || in->bv_val[ 1 ] == '.' ) )
305 1.1 lukem {
306 1.1 lukem char buf[ SLAP_LDAPDN_MAXLEN ];
307 1.1 lukem struct berval id,
308 1.1 lukem user = BER_BVNULL,
309 1.1 lukem realm = BER_BVNULL,
310 1.1 lukem mech = BER_BVNULL;
311 1.1 lukem
312 1.1 lukem if ( sizeof( buf ) <= in->bv_len ) {
313 1.1 lukem return LDAP_INVALID_SYNTAX;
314 1.1 lukem }
315 1.1 lukem
316 1.1 lukem id.bv_len = in->bv_len;
317 1.1 lukem id.bv_val = buf;
318 1.1 lukem strncpy( buf, in->bv_val, sizeof( buf ) );
319 1.1 lukem
320 1.1 lukem rc = slap_parse_user( &id, &user, &realm, &mech );
321 1.1 lukem if ( rc != LDAP_SUCCESS ) {
322 1.1 lukem return LDAP_INVALID_SYNTAX;
323 1.1 lukem }
324 1.1 lukem
325 1.1 lukem return rc;
326 1.1 lukem
327 1.1 lukem /*
328 1.1 lukem * 5) group[/groupClass[/memberAttr]]:<DN>
329 1.1 lukem *
330 1.1 lukem * <groupClass> defaults to "groupOfNames"
331 1.1 lukem * <memberAttr> defaults to "member"
332 1.1 lukem *
333 1.1 lukem * <DN> must pass DN normalization
334 1.1 lukem */
335 1.1 lukem } else if ( strncasecmp( in->bv_val, "group", STRLENOF( "group" ) ) == 0 )
336 1.1 lukem {
337 1.1 lukem struct berval group_dn = BER_BVNULL,
338 1.1 lukem group_oc = BER_BVNULL,
339 1.1 lukem member_at = BER_BVNULL;
340 1.1 lukem
341 1.1 lukem bv.bv_val = in->bv_val + STRLENOF( "group" );
342 1.1 lukem bv.bv_len = in->bv_len - STRLENOF( "group" );
343 1.1 lukem group_dn.bv_val = ber_bvchr( &bv, ':' );
344 1.1 lukem if ( group_dn.bv_val == NULL ) {
345 1.1 lukem /* last chance: assume it's a(n exact) DN ... */
346 1.1 lukem bv.bv_val = in->bv_val;
347 1.1 lukem scope = LDAP_X_SCOPE_EXACT;
348 1.1 lukem goto is_dn;
349 1.1 lukem }
350 1.1 lukem
351 1.1 lukem /*
352 1.1 lukem * FIXME: we assume that "member" and "groupOfNames"
353 1.1 lukem * are present in schema...
354 1.1 lukem */
355 1.1 lukem if ( bv.bv_val[ 0 ] == '/' ) {
356 1.1 lukem group_oc.bv_val = &bv.bv_val[ 1 ];
357 1.1 lukem group_oc.bv_len = group_dn.bv_val - group_oc.bv_val;
358 1.1 lukem
359 1.1 lukem member_at.bv_val = ber_bvchr( &group_oc, '/' );
360 1.1 lukem if ( member_at.bv_val ) {
361 1.1 lukem AttributeDescription *ad = NULL;
362 1.1 lukem const char *text = NULL;
363 1.1 lukem
364 1.1 lukem group_oc.bv_len = member_at.bv_val - group_oc.bv_val;
365 1.1 lukem member_at.bv_val++;
366 1.1 lukem member_at.bv_len = group_dn.bv_val - member_at.bv_val;
367 1.1 lukem rc = slap_bv2ad( &member_at, &ad, &text );
368 1.1 lukem if ( rc != LDAP_SUCCESS ) {
369 1.1 lukem return rc;
370 1.1 lukem }
371 1.1 lukem }
372 1.1 lukem
373 1.1 lukem if ( oc_bvfind( &group_oc ) == NULL ) {
374 1.1 lukem return LDAP_INVALID_SYNTAX;
375 1.1 lukem }
376 1.1 lukem }
377 1.1 lukem
378 1.1 lukem group_dn.bv_val++;
379 1.1 lukem group_dn.bv_len = in->bv_len - ( group_dn.bv_val - in->bv_val );
380 1.1 lukem
381 1.1 lukem rc = dnValidate( NULL, &group_dn );
382 1.1 lukem if ( rc != LDAP_SUCCESS ) {
383 1.1 lukem return rc;
384 1.1 lukem }
385 1.1 lukem
386 1.1 lukem return rc;
387 1.1 lukem }
388 1.1 lukem
389 1.1 lukem /*
390 1.1 lukem * ldap:///<base>??<scope>?<filter>
391 1.1 lukem * <scope> ::= {base|one|subtree}
392 1.1 lukem *
393 1.1 lukem * <scope> defaults to "base"
394 1.1 lukem * <base> must pass DN normalization
395 1.1 lukem * <filter> must pass str2filter()
396 1.1 lukem */
397 1.1 lukem rc = ldap_url_parse( in->bv_val, &ludp );
398 1.1 lukem switch ( rc ) {
399 1.1 lukem case LDAP_URL_SUCCESS:
400 1.1 lukem /* FIXME: the check is pedantic, but I think it's necessary,
401 1.1 lukem * because people tend to use things like ldaps:// which
402 1.1 lukem * gives the idea SSL is being used. Maybe we could
403 1.1 lukem * accept ldapi:// as well, but the point is that we use
404 1.1 lukem * an URL as an easy means to define bits of a search with
405 1.1 lukem * little parsing.
406 1.1 lukem */
407 1.1 lukem if ( strcasecmp( ludp->lud_scheme, "ldap" ) != 0 ) {
408 1.1 lukem /*
409 1.1 lukem * must be ldap:///
410 1.1 lukem */
411 1.1 lukem rc = LDAP_INVALID_SYNTAX;
412 1.1 lukem goto done;
413 1.1 lukem }
414 1.1 lukem break;
415 1.1 lukem
416 1.1 lukem case LDAP_URL_ERR_BADSCHEME:
417 1.1 lukem /*
418 1.1 lukem * last chance: assume it's a(n exact) DN ...
419 1.1 lukem *
420 1.1 lukem * NOTE: must pass DN normalization
421 1.1 lukem */
422 1.1 lukem ldap_free_urldesc( ludp );
423 1.1 lukem bv.bv_val = in->bv_val;
424 1.1 lukem scope = LDAP_X_SCOPE_EXACT;
425 1.1 lukem goto is_dn;
426 1.1 lukem
427 1.1 lukem default:
428 1.1 lukem rc = LDAP_INVALID_SYNTAX;
429 1.1 lukem goto done;
430 1.1 lukem }
431 1.1 lukem
432 1.1 lukem if ( ( ludp->lud_host && *ludp->lud_host )
433 1.1 lukem || ludp->lud_attrs || ludp->lud_exts )
434 1.1 lukem {
435 1.1 lukem /* host part must be empty */
436 1.1 lukem /* attrs and extensions parts must be empty */
437 1.1 lukem rc = LDAP_INVALID_SYNTAX;
438 1.1 lukem goto done;
439 1.1 lukem }
440 1.1 lukem
441 1.1 lukem /* Grab the filter */
442 1.1 lukem if ( ludp->lud_filter ) {
443 1.1 lukem Filter *f = str2filter( ludp->lud_filter );
444 1.1 lukem if ( f == NULL ) {
445 1.1 lukem rc = LDAP_INVALID_SYNTAX;
446 1.1 lukem goto done;
447 1.1 lukem }
448 1.1 lukem filter_free( f );
449 1.1 lukem }
450 1.1 lukem
451 1.1 lukem /* Grab the searchbase */
452 1.1 lukem assert( ludp->lud_dn != NULL );
453 1.1 lukem ber_str2bv( ludp->lud_dn, 0, 0, &bv );
454 1.1 lukem rc = dnValidate( NULL, &bv );
455 1.1 lukem
456 1.1 lukem done:
457 1.1 lukem ldap_free_urldesc( ludp );
458 1.1 lukem return( rc );
459 1.1 lukem }
460 1.1 lukem
461 1.1 lukem static int
462 1.1 lukem authzPrettyNormal(
463 1.1 lukem struct berval *val,
464 1.1 lukem struct berval *normalized,
465 1.1 lukem void *ctx,
466 1.1 lukem int normalize )
467 1.1 lukem {
468 1.1 lukem struct berval bv;
469 1.1 lukem int rc = LDAP_INVALID_SYNTAX;
470 1.1 lukem LDAPURLDesc *ludp = NULL;
471 1.1 lukem char *lud_dn = NULL,
472 1.1 lukem *lud_filter = NULL;
473 1.1 lukem int scope = -1;
474 1.1 lukem
475 1.1 lukem /*
476 1.1 lukem * 1) <DN>
477 1.1 lukem * 2) dn[.{exact|children|subtree|onelevel}]:{*|<DN>}
478 1.1 lukem * 3) dn.regex:<pattern>
479 1.1 lukem * 4) u[.mech[/realm]]:<ID>
480 1.1 lukem * 5) group[/<groupClass>[/<memberAttr>]]:<DN>
481 1.1 lukem * 6) <URL>
482 1.1 lukem */
483 1.1 lukem
484 1.1 lukem assert( val != NULL );
485 1.1 lukem assert( !BER_BVISNULL( val ) );
486 1.1 lukem
487 1.1 lukem /*
488 1.1 lukem * 2) dn[.{exact|children|subtree|onelevel}]:{*|<DN>}
489 1.1 lukem * 3) dn.regex:<pattern>
490 1.1 lukem *
491 1.1 lukem * <DN> must pass DN normalization
492 1.1 lukem */
493 1.1 lukem if ( !strncasecmp( val->bv_val, "dn", STRLENOF( "dn" ) ) ) {
494 1.1 lukem struct berval out = BER_BVNULL,
495 1.1 lukem prefix = BER_BVNULL;
496 1.1 lukem char *ptr;
497 1.1 lukem
498 1.1 lukem bv.bv_val = val->bv_val + STRLENOF( "dn" );
499 1.1 lukem
500 1.1 lukem if ( bv.bv_val[ 0 ] == '.' ) {
501 1.1 lukem bv.bv_val++;
502 1.1 lukem
503 1.1 lukem if ( !strncasecmp( bv.bv_val, "exact:", STRLENOF( "exact:" ) ) ) {
504 1.1 lukem bv.bv_val += STRLENOF( "exact:" );
505 1.1 lukem scope = LDAP_X_SCOPE_EXACT;
506 1.1 lukem
507 1.1 lukem } else if ( !strncasecmp( bv.bv_val, "regex:", STRLENOF( "regex:" ) ) ) {
508 1.1 lukem bv.bv_val += STRLENOF( "regex:" );
509 1.1 lukem scope = LDAP_X_SCOPE_REGEX;
510 1.1 lukem
511 1.1 lukem } else if ( !strncasecmp( bv.bv_val, "children:", STRLENOF( "children:" ) ) ) {
512 1.1 lukem bv.bv_val += STRLENOF( "children:" );
513 1.1 lukem scope = LDAP_X_SCOPE_CHILDREN;
514 1.1 lukem
515 1.1 lukem } else if ( !strncasecmp( bv.bv_val, "subtree:", STRLENOF( "subtree:" ) ) ) {
516 1.1 lukem bv.bv_val += STRLENOF( "subtree:" );
517 1.1 lukem scope = LDAP_X_SCOPE_SUBTREE;
518 1.1 lukem
519 1.1 lukem } else if ( !strncasecmp( bv.bv_val, "onelevel:", STRLENOF( "onelevel:" ) ) ) {
520 1.1 lukem bv.bv_val += STRLENOF( "onelevel:" );
521 1.1 lukem scope = LDAP_X_SCOPE_ONELEVEL;
522 1.1 lukem
523 1.1 lukem } else {
524 1.1 lukem return LDAP_INVALID_SYNTAX;
525 1.1 lukem }
526 1.1 lukem
527 1.1 lukem } else {
528 1.1 lukem if ( bv.bv_val[ 0 ] != ':' ) {
529 1.1 lukem return LDAP_INVALID_SYNTAX;
530 1.1 lukem }
531 1.1 lukem scope = LDAP_X_SCOPE_EXACT;
532 1.1 lukem bv.bv_val++;
533 1.1 lukem }
534 1.1 lukem
535 1.1 lukem bv.bv_val += strspn( bv.bv_val, " " );
536 1.1 lukem /* jump here in case no type specification was present
537 1.1 lukem * and uri was not an URI... HEADS-UP: assuming EXACT */
538 1.1 lukem is_dn: bv.bv_len = val->bv_len - ( bv.bv_val - val->bv_val );
539 1.1 lukem
540 1.1 lukem /* a single '*' means any DN without using regexes */
541 1.1 lukem if ( ber_bvccmp( &bv, '*' ) ) {
542 1.1 lukem ber_str2bv_x( "dn:*", STRLENOF( "dn:*" ), 1, normalized, ctx );
543 1.1 lukem return LDAP_SUCCESS;
544 1.1 lukem }
545 1.1 lukem
546 1.1 lukem switch ( scope ) {
547 1.1 lukem case LDAP_X_SCOPE_EXACT:
548 1.1 lukem case LDAP_X_SCOPE_CHILDREN:
549 1.1 lukem case LDAP_X_SCOPE_SUBTREE:
550 1.1 lukem case LDAP_X_SCOPE_ONELEVEL:
551 1.1 lukem if ( normalize ) {
552 1.1 lukem rc = dnNormalize( 0, NULL, NULL, &bv, &out, ctx );
553 1.1 lukem } else {
554 1.1 lukem rc = dnPretty( NULL, &bv, &out, ctx );
555 1.1 lukem }
556 1.1 lukem if( rc != LDAP_SUCCESS ) {
557 1.1 lukem return LDAP_INVALID_SYNTAX;
558 1.1 lukem }
559 1.1 lukem break;
560 1.1 lukem
561 1.1 lukem case LDAP_X_SCOPE_REGEX:
562 1.1 lukem normalized->bv_len = STRLENOF( "dn.regex:" ) + bv.bv_len;
563 1.1 lukem normalized->bv_val = ber_memalloc_x( normalized->bv_len + 1, ctx );
564 1.1 lukem ptr = lutil_strcopy( normalized->bv_val, "dn.regex:" );
565 1.1 lukem ptr = lutil_strncopy( ptr, bv.bv_val, bv.bv_len );
566 1.1 lukem ptr[ 0 ] = '\0';
567 1.1 lukem return LDAP_SUCCESS;
568 1.1 lukem
569 1.1 lukem default:
570 1.1 lukem return LDAP_INVALID_SYNTAX;
571 1.1 lukem }
572 1.1 lukem
573 1.1 lukem /* prepare prefix */
574 1.1 lukem switch ( scope ) {
575 1.1 lukem case LDAP_X_SCOPE_EXACT:
576 1.1 lukem BER_BVSTR( &prefix, "dn:" );
577 1.1 lukem break;
578 1.1 lukem
579 1.1 lukem case LDAP_X_SCOPE_CHILDREN:
580 1.1 lukem BER_BVSTR( &prefix, "dn.children:" );
581 1.1 lukem break;
582 1.1 lukem
583 1.1 lukem case LDAP_X_SCOPE_SUBTREE:
584 1.1 lukem BER_BVSTR( &prefix, "dn.subtree:" );
585 1.1 lukem break;
586 1.1 lukem
587 1.1 lukem case LDAP_X_SCOPE_ONELEVEL:
588 1.1 lukem BER_BVSTR( &prefix, "dn.onelevel:" );
589 1.1 lukem break;
590 1.1 lukem
591 1.1 lukem default:
592 1.1 lukem assert( 0 );
593 1.1 lukem break;
594 1.1 lukem }
595 1.1 lukem
596 1.1 lukem normalized->bv_len = prefix.bv_len + out.bv_len;
597 1.1 lukem normalized->bv_val = ber_memalloc_x( normalized->bv_len + 1, ctx );
598 1.1 lukem
599 1.1 lukem ptr = lutil_strcopy( normalized->bv_val, prefix.bv_val );
600 1.1 lukem ptr = lutil_strncopy( ptr, out.bv_val, out.bv_len );
601 1.1 lukem ptr[ 0 ] = '\0';
602 1.1 lukem ber_memfree_x( out.bv_val, ctx );
603 1.1 lukem
604 1.1 lukem return LDAP_SUCCESS;
605 1.1 lukem
606 1.1 lukem /*
607 1.1 lukem * 4) u[.mech[/realm]]:<ID>
608 1.1 lukem */
609 1.1 lukem } else if ( ( val->bv_val[ 0 ] == 'u' || val->bv_val[ 0 ] == 'U' )
610 1.1 lukem && ( val->bv_val[ 1 ] == ':'
611 1.1 lukem || val->bv_val[ 1 ] == '/'
612 1.1 lukem || val->bv_val[ 1 ] == '.' ) )
613 1.1 lukem {
614 1.1 lukem char buf[ SLAP_LDAPDN_MAXLEN ];
615 1.1 lukem struct berval id,
616 1.1 lukem user = BER_BVNULL,
617 1.1 lukem realm = BER_BVNULL,
618 1.1 lukem mech = BER_BVNULL;
619 1.1 lukem
620 1.1 lukem if ( sizeof( buf ) <= val->bv_len ) {
621 1.1 lukem return LDAP_INVALID_SYNTAX;
622 1.1 lukem }
623 1.1 lukem
624 1.1 lukem id.bv_len = val->bv_len;
625 1.1 lukem id.bv_val = buf;
626 1.1 lukem strncpy( buf, val->bv_val, sizeof( buf ) );
627 1.1 lukem
628 1.1 lukem rc = slap_parse_user( &id, &user, &realm, &mech );
629 1.1 lukem if ( rc != LDAP_SUCCESS ) {
630 1.1 lukem return LDAP_INVALID_SYNTAX;
631 1.1 lukem }
632 1.1 lukem
633 1.1 lukem ber_dupbv_x( normalized, val, ctx );
634 1.1 lukem
635 1.1 lukem return rc;
636 1.1 lukem
637 1.1 lukem /*
638 1.1 lukem * 5) group[/groupClass[/memberAttr]]:<DN>
639 1.1 lukem *
640 1.1 lukem * <groupClass> defaults to "groupOfNames"
641 1.1 lukem * <memberAttr> defaults to "member"
642 1.1 lukem *
643 1.1 lukem * <DN> must pass DN normalization
644 1.1 lukem */
645 1.1 lukem } else if ( strncasecmp( val->bv_val, "group", STRLENOF( "group" ) ) == 0 )
646 1.1 lukem {
647 1.1 lukem struct berval group_dn = BER_BVNULL,
648 1.1 lukem group_oc = BER_BVNULL,
649 1.1 lukem member_at = BER_BVNULL,
650 1.1 lukem out = BER_BVNULL;
651 1.1 lukem char *ptr;
652 1.1 lukem
653 1.1 lukem bv.bv_val = val->bv_val + STRLENOF( "group" );
654 1.1 lukem bv.bv_len = val->bv_len - STRLENOF( "group" );
655 1.1 lukem group_dn.bv_val = ber_bvchr( &bv, ':' );
656 1.1 lukem if ( group_dn.bv_val == NULL ) {
657 1.1 lukem /* last chance: assume it's a(n exact) DN ... */
658 1.1 lukem bv.bv_val = val->bv_val;
659 1.1 lukem scope = LDAP_X_SCOPE_EXACT;
660 1.1 lukem goto is_dn;
661 1.1 lukem }
662 1.1 lukem
663 1.1 lukem /*
664 1.1 lukem * FIXME: we assume that "member" and "groupOfNames"
665 1.1 lukem * are present in schema...
666 1.1 lukem */
667 1.1 lukem if ( bv.bv_val[ 0 ] == '/' ) {
668 1.1 lukem ObjectClass *oc = NULL;
669 1.1 lukem
670 1.1 lukem group_oc.bv_val = &bv.bv_val[ 1 ];
671 1.1 lukem group_oc.bv_len = group_dn.bv_val - group_oc.bv_val;
672 1.1 lukem
673 1.1 lukem member_at.bv_val = ber_bvchr( &group_oc, '/' );
674 1.1 lukem if ( member_at.bv_val ) {
675 1.1 lukem AttributeDescription *ad = NULL;
676 1.1 lukem const char *text = NULL;
677 1.1 lukem
678 1.1 lukem group_oc.bv_len = member_at.bv_val - group_oc.bv_val;
679 1.1 lukem member_at.bv_val++;
680 1.1 lukem member_at.bv_len = group_dn.bv_val - member_at.bv_val;
681 1.1 lukem rc = slap_bv2ad( &member_at, &ad, &text );
682 1.1 lukem if ( rc != LDAP_SUCCESS ) {
683 1.1 lukem return rc;
684 1.1 lukem }
685 1.1 lukem
686 1.1 lukem member_at = ad->ad_cname;
687 1.1 lukem
688 1.1 lukem }
689 1.1 lukem
690 1.1 lukem oc = oc_bvfind( &group_oc );
691 1.1 lukem if ( oc == NULL ) {
692 1.1 lukem return LDAP_INVALID_SYNTAX;
693 1.1 lukem }
694 1.1 lukem
695 1.1 lukem group_oc = oc->soc_cname;
696 1.1 lukem }
697 1.1 lukem
698 1.1 lukem group_dn.bv_val++;
699 1.1 lukem group_dn.bv_len = val->bv_len - ( group_dn.bv_val - val->bv_val );
700 1.1 lukem
701 1.1 lukem if ( normalize ) {
702 1.1 lukem rc = dnNormalize( 0, NULL, NULL, &group_dn, &out, ctx );
703 1.1 lukem } else {
704 1.1 lukem rc = dnPretty( NULL, &group_dn, &out, ctx );
705 1.1 lukem }
706 1.1 lukem if ( rc != LDAP_SUCCESS ) {
707 1.1 lukem return rc;
708 1.1 lukem }
709 1.1 lukem
710 1.1 lukem normalized->bv_len = STRLENOF( "group" ":" ) + out.bv_len;
711 1.1 lukem if ( !BER_BVISNULL( &group_oc ) ) {
712 1.1 lukem normalized->bv_len += STRLENOF( "/" ) + group_oc.bv_len;
713 1.1 lukem if ( !BER_BVISNULL( &member_at ) ) {
714 1.1 lukem normalized->bv_len += STRLENOF( "/" ) + member_at.bv_len;
715 1.1 lukem }
716 1.1 lukem }
717 1.1 lukem
718 1.1 lukem normalized->bv_val = ber_memalloc_x( normalized->bv_len + 1, ctx );
719 1.1 lukem ptr = lutil_strcopy( normalized->bv_val, "group" );
720 1.1 lukem if ( !BER_BVISNULL( &group_oc ) ) {
721 1.1 lukem ptr[ 0 ] = '/';
722 1.1 lukem ptr++;
723 1.1 lukem ptr = lutil_strncopy( ptr, group_oc.bv_val, group_oc.bv_len );
724 1.1 lukem if ( !BER_BVISNULL( &member_at ) ) {
725 1.1 lukem ptr[ 0 ] = '/';
726 1.1 lukem ptr++;
727 1.1 lukem ptr = lutil_strncopy( ptr, member_at.bv_val, member_at.bv_len );
728 1.1 lukem }
729 1.1 lukem }
730 1.1 lukem ptr[ 0 ] = ':';
731 1.1 lukem ptr++;
732 1.1 lukem ptr = lutil_strncopy( ptr, out.bv_val, out.bv_len );
733 1.1 lukem ptr[ 0 ] = '\0';
734 1.1 lukem ber_memfree_x( out.bv_val, ctx );
735 1.1 lukem
736 1.1 lukem return rc;
737 1.1 lukem }
738 1.1 lukem
739 1.1 lukem /*
740 1.1 lukem * ldap:///<base>??<scope>?<filter>
741 1.1 lukem * <scope> ::= {base|one|subtree}
742 1.1 lukem *
743 1.1 lukem * <scope> defaults to "base"
744 1.1 lukem * <base> must pass DN normalization
745 1.1 lukem * <filter> must pass str2filter()
746 1.1 lukem */
747 1.1 lukem rc = ldap_url_parse( val->bv_val, &ludp );
748 1.1 lukem switch ( rc ) {
749 1.1 lukem case LDAP_URL_SUCCESS:
750 1.1 lukem /* FIXME: the check is pedantic, but I think it's necessary,
751 1.1 lukem * because people tend to use things like ldaps:// which
752 1.1 lukem * gives the idea SSL is being used. Maybe we could
753 1.1 lukem * accept ldapi:// as well, but the point is that we use
754 1.1 lukem * an URL as an easy means to define bits of a search with
755 1.1 lukem * little parsing.
756 1.1 lukem */
757 1.1 lukem if ( strcasecmp( ludp->lud_scheme, "ldap" ) != 0 ) {
758 1.1 lukem /*
759 1.1 lukem * must be ldap:///
760 1.1 lukem */
761 1.1 lukem rc = LDAP_INVALID_SYNTAX;
762 1.1 lukem goto done;
763 1.1 lukem }
764 1.1 lukem
765 1.1 lukem AC_MEMCPY( ludp->lud_scheme, "ldap", STRLENOF( "ldap" ) );
766 1.1 lukem break;
767 1.1 lukem
768 1.1 lukem case LDAP_URL_ERR_BADSCHEME:
769 1.1 lukem /*
770 1.1 lukem * last chance: assume it's a(n exact) DN ...
771 1.1 lukem *
772 1.1 lukem * NOTE: must pass DN normalization
773 1.1 lukem */
774 1.1 lukem ldap_free_urldesc( ludp );
775 1.1 lukem bv.bv_val = val->bv_val;
776 1.1 lukem scope = LDAP_X_SCOPE_EXACT;
777 1.1 lukem goto is_dn;
778 1.1 lukem
779 1.1 lukem default:
780 1.1 lukem rc = LDAP_INVALID_SYNTAX;
781 1.1 lukem goto done;
782 1.1 lukem }
783 1.1 lukem
784 1.1 lukem if ( ( ludp->lud_host && *ludp->lud_host )
785 1.1 lukem || ludp->lud_attrs || ludp->lud_exts )
786 1.1 lukem {
787 1.1 lukem /* host part must be empty */
788 1.1 lukem /* attrs and extensions parts must be empty */
789 1.1 lukem rc = LDAP_INVALID_SYNTAX;
790 1.1 lukem goto done;
791 1.1 lukem }
792 1.1 lukem
793 1.1 lukem /* Grab the filter */
794 1.1 lukem if ( ludp->lud_filter ) {
795 1.1 lukem struct berval filterstr;
796 1.1 lukem Filter *f;
797 1.1 lukem
798 1.1 lukem lud_filter = ludp->lud_filter;
799 1.1 lukem
800 1.1 lukem f = str2filter( lud_filter );
801 1.1 lukem if ( f == NULL ) {
802 1.1 lukem rc = LDAP_INVALID_SYNTAX;
803 1.1 lukem goto done;
804 1.1 lukem }
805 1.1 lukem filter2bv( f, &filterstr );
806 1.1 lukem filter_free( f );
807 1.1 lukem if ( BER_BVISNULL( &filterstr ) ) {
808 1.1 lukem rc = LDAP_INVALID_SYNTAX;
809 1.1 lukem goto done;
810 1.1 lukem }
811 1.1 lukem
812 1.1 lukem ludp->lud_filter = filterstr.bv_val;
813 1.1 lukem }
814 1.1 lukem
815 1.1 lukem /* Grab the searchbase */
816 1.1 lukem assert( ludp->lud_dn != NULL );
817 1.1 lukem if ( ludp->lud_dn ) {
818 1.1 lukem struct berval out = BER_BVNULL;
819 1.1 lukem
820 1.1 lukem lud_dn = ludp->lud_dn;
821 1.1 lukem
822 1.1 lukem ber_str2bv( lud_dn, 0, 0, &bv );
823 1.1 lukem if ( normalize ) {
824 1.1 lukem rc = dnNormalize( 0, NULL, NULL, &bv, &out, ctx );
825 1.1 lukem } else {
826 1.1 lukem rc = dnPretty( NULL, &bv, &out, ctx );
827 1.1 lukem }
828 1.1 lukem
829 1.1 lukem if ( rc != LDAP_SUCCESS ) {
830 1.1 lukem goto done;
831 1.1 lukem }
832 1.1 lukem
833 1.1 lukem ludp->lud_dn = out.bv_val;
834 1.1 lukem }
835 1.1 lukem
836 1.1 lukem ludp->lud_port = 0;
837 1.1 lukem normalized->bv_val = ldap_url_desc2str( ludp );
838 1.1 lukem if ( normalized->bv_val ) {
839 1.1 lukem normalized->bv_len = strlen( normalized->bv_val );
840 1.1 lukem
841 1.1 lukem } else {
842 1.1 lukem rc = LDAP_INVALID_SYNTAX;
843 1.1 lukem }
844 1.1 lukem
845 1.1 lukem done:
846 1.1 lukem if ( lud_filter ) {
847 1.1 lukem if ( ludp->lud_filter != lud_filter ) {
848 1.1 lukem ber_memfree( ludp->lud_filter );
849 1.1 lukem }
850 1.1 lukem ludp->lud_filter = lud_filter;
851 1.1 lukem }
852 1.1 lukem
853 1.1 lukem if ( lud_dn ) {
854 1.1 lukem if ( ludp->lud_dn != lud_dn ) {
855 1.1 lukem ber_memfree( ludp->lud_dn );
856 1.1 lukem }
857 1.1 lukem ludp->lud_dn = lud_dn;
858 1.1 lukem }
859 1.1 lukem
860 1.1 lukem ldap_free_urldesc( ludp );
861 1.1 lukem
862 1.1 lukem return( rc );
863 1.1 lukem }
864 1.1 lukem
865 1.1 lukem int
866 1.1 lukem authzNormalize(
867 1.1 lukem slap_mask_t usage,
868 1.1 lukem Syntax *syntax,
869 1.1 lukem MatchingRule *mr,
870 1.1 lukem struct berval *val,
871 1.1 lukem struct berval *normalized,
872 1.1 lukem void *ctx )
873 1.1 lukem {
874 1.1 lukem int rc;
875 1.1 lukem
876 1.1 lukem Debug( LDAP_DEBUG_TRACE, ">>> authzNormalize: <%s>\n",
877 1.1 lukem val->bv_val, 0, 0 );
878 1.1 lukem
879 1.1 lukem rc = authzPrettyNormal( val, normalized, ctx, 1 );
880 1.1 lukem
881 1.1 lukem Debug( LDAP_DEBUG_TRACE, "<<< authzNormalize: <%s> (%d)\n",
882 1.1 lukem normalized->bv_val, rc, 0 );
883 1.1 lukem
884 1.1 lukem return rc;
885 1.1 lukem }
886 1.1 lukem
887 1.1 lukem int
888 1.1 lukem authzPretty(
889 1.1 lukem Syntax *syntax,
890 1.1 lukem struct berval *val,
891 1.1 lukem struct berval *out,
892 1.1 lukem void *ctx)
893 1.1 lukem {
894 1.1 lukem int rc;
895 1.1 lukem
896 1.1 lukem Debug( LDAP_DEBUG_TRACE, ">>> authzPretty: <%s>\n",
897 1.1 lukem val->bv_val, 0, 0 );
898 1.1 lukem
899 1.1 lukem rc = authzPrettyNormal( val, out, ctx, 0 );
900 1.1 lukem
901 1.1 lukem Debug( LDAP_DEBUG_TRACE, "<<< authzPretty: <%s> (%d)\n",
902 1.1 lukem out->bv_val, rc, 0 );
903 1.1 lukem
904 1.1 lukem return rc;
905 1.1 lukem }
906 1.1 lukem
907 1.1 lukem
908 1.1 lukem static int
909 1.1 lukem slap_parseURI(
910 1.1 lukem Operation *op,
911 1.1 lukem struct berval *uri,
912 1.1 lukem struct berval *base,
913 1.1 lukem struct berval *nbase,
914 1.1 lukem int *scope,
915 1.1 lukem Filter **filter,
916 1.1 lukem struct berval *fstr,
917 1.1 lukem int normalize )
918 1.1 lukem {
919 1.1 lukem struct berval bv;
920 1.1 lukem int rc;
921 1.1 lukem LDAPURLDesc *ludp;
922 1.1 lukem
923 1.1 lukem struct berval idx;
924 1.1 lukem
925 1.1 lukem assert( uri != NULL && !BER_BVISNULL( uri ) );
926 1.1 lukem BER_BVZERO( base );
927 1.1 lukem BER_BVZERO( nbase );
928 1.1 lukem BER_BVZERO( fstr );
929 1.1 lukem *scope = -1;
930 1.1 lukem *filter = NULL;
931 1.1 lukem
932 1.1 lukem Debug( LDAP_DEBUG_TRACE,
933 1.1 lukem "slap_parseURI: parsing %s\n", uri->bv_val, 0, 0 );
934 1.1 lukem
935 1.1 lukem rc = LDAP_PROTOCOL_ERROR;
936 1.1 lukem
937 1.1 lukem idx = *uri;
938 1.1 lukem if ( idx.bv_val[ 0 ] == '{' ) {
939 1.1 lukem char *ptr;
940 1.1 lukem
941 1.1 lukem ptr = ber_bvchr( &idx, '}' ) + 1;
942 1.1 lukem
943 1.1 lukem assert( ptr != (void *)1 );
944 1.1 lukem
945 1.1 lukem idx.bv_len -= ptr - idx.bv_val;
946 1.1 lukem idx.bv_val = ptr;
947 1.1 lukem uri = &idx;
948 1.1 lukem }
949 1.1 lukem
950 1.1 lukem /*
951 1.1 lukem * dn[.<dnstyle>]:<dnpattern>
952 1.1 lukem * <dnstyle> ::= {exact|regex|children|subtree|onelevel}
953 1.1 lukem *
954 1.1 lukem * <dnstyle> defaults to "exact"
955 1.1 lukem * if <dnstyle> is not "regex", <dnpattern> must pass DN normalization
956 1.1 lukem */
957 1.1 lukem if ( !strncasecmp( uri->bv_val, "dn", STRLENOF( "dn" ) ) ) {
958 1.1 lukem bv.bv_val = uri->bv_val + STRLENOF( "dn" );
959 1.1 lukem
960 1.1 lukem if ( bv.bv_val[ 0 ] == '.' ) {
961 1.1 lukem bv.bv_val++;
962 1.1 lukem
963 1.1 lukem if ( !strncasecmp( bv.bv_val, "exact:", STRLENOF( "exact:" ) ) ) {
964 1.1 lukem bv.bv_val += STRLENOF( "exact:" );
965 1.1 lukem *scope = LDAP_X_SCOPE_EXACT;
966 1.1 lukem
967 1.1 lukem } else if ( !strncasecmp( bv.bv_val, "regex:", STRLENOF( "regex:" ) ) ) {
968 1.1 lukem bv.bv_val += STRLENOF( "regex:" );
969 1.1 lukem *scope = LDAP_X_SCOPE_REGEX;
970 1.1 lukem
971 1.1 lukem } else if ( !strncasecmp( bv.bv_val, "children:", STRLENOF( "children:" ) ) ) {
972 1.1 lukem bv.bv_val += STRLENOF( "children:" );
973 1.1 lukem *scope = LDAP_X_SCOPE_CHILDREN;
974 1.1 lukem
975 1.1 lukem } else if ( !strncasecmp( bv.bv_val, "subtree:", STRLENOF( "subtree:" ) ) ) {
976 1.1 lukem bv.bv_val += STRLENOF( "subtree:" );
977 1.1 lukem *scope = LDAP_X_SCOPE_SUBTREE;
978 1.1 lukem
979 1.1 lukem } else if ( !strncasecmp( bv.bv_val, "onelevel:", STRLENOF( "onelevel:" ) ) ) {
980 1.1 lukem bv.bv_val += STRLENOF( "onelevel:" );
981 1.1 lukem *scope = LDAP_X_SCOPE_ONELEVEL;
982 1.1 lukem
983 1.1 lukem } else {
984 1.1 lukem return LDAP_PROTOCOL_ERROR;
985 1.1 lukem }
986 1.1 lukem
987 1.1 lukem } else {
988 1.1 lukem if ( bv.bv_val[ 0 ] != ':' ) {
989 1.1 lukem return LDAP_PROTOCOL_ERROR;
990 1.1 lukem }
991 1.1 lukem *scope = LDAP_X_SCOPE_EXACT;
992 1.1 lukem bv.bv_val++;
993 1.1 lukem }
994 1.1 lukem
995 1.1 lukem bv.bv_val += strspn( bv.bv_val, " " );
996 1.1 lukem /* jump here in case no type specification was present
997 1.1 lukem * and uri was not an URI... HEADS-UP: assuming EXACT */
998 1.1 lukem is_dn: bv.bv_len = uri->bv_len - (bv.bv_val - uri->bv_val);
999 1.1 lukem
1000 1.1 lukem /* a single '*' means any DN without using regexes */
1001 1.1 lukem if ( ber_bvccmp( &bv, '*' ) ) {
1002 1.1 lukem *scope = LDAP_X_SCOPE_USERS;
1003 1.1 lukem }
1004 1.1 lukem
1005 1.1 lukem switch ( *scope ) {
1006 1.1 lukem case LDAP_X_SCOPE_EXACT:
1007 1.1 lukem case LDAP_X_SCOPE_CHILDREN:
1008 1.1 lukem case LDAP_X_SCOPE_SUBTREE:
1009 1.1 lukem case LDAP_X_SCOPE_ONELEVEL:
1010 1.1 lukem if ( normalize ) {
1011 1.1 lukem rc = dnNormalize( 0, NULL, NULL, &bv, nbase, op->o_tmpmemctx );
1012 1.1 lukem if( rc != LDAP_SUCCESS ) {
1013 1.1 lukem *scope = -1;
1014 1.1 lukem }
1015 1.1 lukem } else {
1016 1.1 lukem ber_dupbv_x( nbase, &bv, op->o_tmpmemctx );
1017 1.1 lukem rc = LDAP_SUCCESS;
1018 1.1 lukem }
1019 1.1 lukem break;
1020 1.1 lukem
1021 1.1 lukem case LDAP_X_SCOPE_REGEX:
1022 1.1 lukem ber_dupbv_x( nbase, &bv, op->o_tmpmemctx );
1023 1.1 lukem
1024 1.1 lukem case LDAP_X_SCOPE_USERS:
1025 1.1 lukem rc = LDAP_SUCCESS;
1026 1.1 lukem break;
1027 1.1 lukem
1028 1.1 lukem default:
1029 1.1 lukem *scope = -1;
1030 1.1 lukem break;
1031 1.1 lukem }
1032 1.1 lukem
1033 1.1 lukem return rc;
1034 1.1 lukem
1035 1.1 lukem /*
1036 1.1 lukem * u:<uid>
1037 1.1 lukem */
1038 1.1 lukem } else if ( ( uri->bv_val[ 0 ] == 'u' || uri->bv_val[ 0 ] == 'U' )
1039 1.1 lukem && ( uri->bv_val[ 1 ] == ':'
1040 1.1 lukem || uri->bv_val[ 1 ] == '/'
1041 1.1 lukem || uri->bv_val[ 1 ] == '.' ) )
1042 1.1 lukem {
1043 1.1 lukem Connection c = *op->o_conn;
1044 1.1 lukem char buf[ SLAP_LDAPDN_MAXLEN ];
1045 1.1 lukem struct berval id,
1046 1.1 lukem user = BER_BVNULL,
1047 1.1 lukem realm = BER_BVNULL,
1048 1.1 lukem mech = BER_BVNULL;
1049 1.1 lukem
1050 1.1 lukem if ( sizeof( buf ) <= uri->bv_len ) {
1051 1.1 lukem return LDAP_INVALID_SYNTAX;
1052 1.1 lukem }
1053 1.1 lukem
1054 1.1 lukem id.bv_len = uri->bv_len;
1055 1.1 lukem id.bv_val = buf;
1056 1.1 lukem strncpy( buf, uri->bv_val, sizeof( buf ) );
1057 1.1 lukem
1058 1.1 lukem rc = slap_parse_user( &id, &user, &realm, &mech );
1059 1.1 lukem if ( rc != LDAP_SUCCESS ) {
1060 1.1 lukem return rc;
1061 1.1 lukem }
1062 1.1 lukem
1063 1.1 lukem if ( !BER_BVISNULL( &mech ) ) {
1064 1.1 lukem c.c_sasl_bind_mech = mech;
1065 1.1 lukem } else {
1066 1.1 lukem BER_BVSTR( &c.c_sasl_bind_mech, "AUTHZ" );
1067 1.1 lukem }
1068 1.1 lukem
1069 1.1 lukem rc = slap_sasl_getdn( &c, op, &user,
1070 1.1 lukem realm.bv_val, nbase, SLAP_GETDN_AUTHZID );
1071 1.1 lukem
1072 1.1 lukem if ( rc == LDAP_SUCCESS ) {
1073 1.1 lukem *scope = LDAP_X_SCOPE_EXACT;
1074 1.1 lukem }
1075 1.1 lukem
1076 1.1 lukem return rc;
1077 1.1 lukem
1078 1.1 lukem /*
1079 1.1 lukem * group[/<groupoc>[/<groupat>]]:<groupdn>
1080 1.1 lukem *
1081 1.1 lukem * groupoc defaults to "groupOfNames"
1082 1.1 lukem * groupat defaults to "member"
1083 1.1 lukem *
1084 1.1 lukem * <groupdn> must pass DN normalization
1085 1.1 lukem */
1086 1.1 lukem } else if ( strncasecmp( uri->bv_val, "group", STRLENOF( "group" ) ) == 0 )
1087 1.1 lukem {
1088 1.1 lukem struct berval group_dn = BER_BVNULL,
1089 1.1 lukem group_oc = BER_BVNULL,
1090 1.1 lukem member_at = BER_BVNULL;
1091 1.1 lukem char *tmp;
1092 1.1 lukem
1093 1.1 lukem bv.bv_val = uri->bv_val + STRLENOF( "group" );
1094 1.1 lukem bv.bv_len = uri->bv_len - STRLENOF( "group" );
1095 1.1 lukem group_dn.bv_val = ber_bvchr( &bv, ':' );
1096 1.1 lukem if ( group_dn.bv_val == NULL ) {
1097 1.1 lukem /* last chance: assume it's a(n exact) DN ... */
1098 1.1 lukem bv.bv_val = uri->bv_val;
1099 1.1 lukem *scope = LDAP_X_SCOPE_EXACT;
1100 1.1 lukem goto is_dn;
1101 1.1 lukem }
1102 1.1 lukem
1103 1.1 lukem if ( bv.bv_val[ 0 ] == '/' ) {
1104 1.1 lukem group_oc.bv_val = &bv.bv_val[ 1 ];
1105 1.1 lukem group_oc.bv_len = group_dn.bv_val - group_oc.bv_val;
1106 1.1 lukem
1107 1.1 lukem member_at.bv_val = ber_bvchr( &group_oc, '/' );
1108 1.1 lukem if ( member_at.bv_val ) {
1109 1.1 lukem group_oc.bv_len = member_at.bv_val - group_oc.bv_val;
1110 1.1 lukem member_at.bv_val++;
1111 1.1 lukem member_at.bv_len = group_dn.bv_val - member_at.bv_val;
1112 1.1 lukem
1113 1.1 lukem } else {
1114 1.1 lukem BER_BVSTR( &member_at, SLAPD_GROUP_ATTR );
1115 1.1 lukem }
1116 1.1 lukem
1117 1.1 lukem } else {
1118 1.1 lukem BER_BVSTR( &group_oc, SLAPD_GROUP_CLASS );
1119 1.1 lukem BER_BVSTR( &member_at, SLAPD_GROUP_ATTR );
1120 1.1 lukem }
1121 1.1 lukem group_dn.bv_val++;
1122 1.1 lukem group_dn.bv_len = uri->bv_len - ( group_dn.bv_val - uri->bv_val );
1123 1.1 lukem
1124 1.1 lukem if ( normalize ) {
1125 1.1 lukem rc = dnNormalize( 0, NULL, NULL, &group_dn, nbase, op->o_tmpmemctx );
1126 1.1 lukem if ( rc != LDAP_SUCCESS ) {
1127 1.1 lukem *scope = -1;
1128 1.1 lukem return rc;
1129 1.1 lukem }
1130 1.1 lukem } else {
1131 1.1 lukem ber_dupbv_x( nbase, &group_dn, op->o_tmpmemctx );
1132 1.1 lukem rc = LDAP_SUCCESS;
1133 1.1 lukem }
1134 1.1 lukem *scope = LDAP_X_SCOPE_GROUP;
1135 1.1 lukem
1136 1.1 lukem /* FIXME: caller needs to add value of member attribute
1137 1.1 lukem * and close brackets twice */
1138 1.1 lukem fstr->bv_len = STRLENOF( "(&(objectClass=)(=" /* )) */ )
1139 1.1 lukem + group_oc.bv_len + member_at.bv_len;
1140 1.1 lukem fstr->bv_val = ch_malloc( fstr->bv_len + 1 );
1141 1.1 lukem
1142 1.1 lukem tmp = lutil_strncopy( fstr->bv_val, "(&(objectClass=" /* )) */ ,
1143 1.1 lukem STRLENOF( "(&(objectClass=" /* )) */ ) );
1144 1.1 lukem tmp = lutil_strncopy( tmp, group_oc.bv_val, group_oc.bv_len );
1145 1.1 lukem tmp = lutil_strncopy( tmp, /* ( */ ")(" /* ) */ ,
1146 1.1 lukem STRLENOF( /* ( */ ")(" /* ) */ ) );
1147 1.1 lukem tmp = lutil_strncopy( tmp, member_at.bv_val, member_at.bv_len );
1148 1.1 lukem tmp = lutil_strncopy( tmp, "=", STRLENOF( "=" ) );
1149 1.1 lukem
1150 1.1 lukem return rc;
1151 1.1 lukem }
1152 1.1 lukem
1153 1.1 lukem /*
1154 1.1 lukem * ldap:///<base>??<scope>?<filter>
1155 1.1 lukem * <scope> ::= {base|one|subtree}
1156 1.1 lukem *
1157 1.1 lukem * <scope> defaults to "base"
1158 1.1 lukem * <base> must pass DN normalization
1159 1.1 lukem * <filter> must pass str2filter()
1160 1.1 lukem */
1161 1.1 lukem rc = ldap_url_parse( uri->bv_val, &ludp );
1162 1.1 lukem switch ( rc ) {
1163 1.1 lukem case LDAP_URL_SUCCESS:
1164 1.1 lukem /* FIXME: the check is pedantic, but I think it's necessary,
1165 1.1 lukem * because people tend to use things like ldaps:// which
1166 1.1 lukem * gives the idea SSL is being used. Maybe we could
1167 1.1 lukem * accept ldapi:// as well, but the point is that we use
1168 1.1 lukem * an URL as an easy means to define bits of a search with
1169 1.1 lukem * little parsing.
1170 1.1 lukem */
1171 1.1 lukem if ( strcasecmp( ludp->lud_scheme, "ldap" ) != 0 ) {
1172 1.1 lukem /*
1173 1.1 lukem * must be ldap:///
1174 1.1 lukem */
1175 1.1 lukem rc = LDAP_PROTOCOL_ERROR;
1176 1.1 lukem goto done;
1177 1.1 lukem }
1178 1.1 lukem break;
1179 1.1 lukem
1180 1.1 lukem case LDAP_URL_ERR_BADSCHEME:
1181 1.1 lukem /*
1182 1.1 lukem * last chance: assume it's a(n exact) DN ...
1183 1.1 lukem *
1184 1.1 lukem * NOTE: must pass DN normalization
1185 1.1 lukem */
1186 1.1 lukem ldap_free_urldesc( ludp );
1187 1.1 lukem bv.bv_val = uri->bv_val;
1188 1.1 lukem *scope = LDAP_X_SCOPE_EXACT;
1189 1.1 lukem goto is_dn;
1190 1.1 lukem
1191 1.1 lukem default:
1192 1.1 lukem rc = LDAP_PROTOCOL_ERROR;
1193 1.1 lukem goto done;
1194 1.1 lukem }
1195 1.1 lukem
1196 1.1 lukem if ( ( ludp->lud_host && *ludp->lud_host )
1197 1.1 lukem || ludp->lud_attrs || ludp->lud_exts )
1198 1.1 lukem {
1199 1.1 lukem /* host part must be empty */
1200 1.1 lukem /* attrs and extensions parts must be empty */
1201 1.1 lukem rc = LDAP_PROTOCOL_ERROR;
1202 1.1 lukem goto done;
1203 1.1 lukem }
1204 1.1 lukem
1205 1.1 lukem /* Grab the scope */
1206 1.1 lukem *scope = ludp->lud_scope;
1207 1.1 lukem
1208 1.1 lukem /* Grab the filter */
1209 1.1 lukem if ( ludp->lud_filter ) {
1210 1.1 lukem *filter = str2filter_x( op, ludp->lud_filter );
1211 1.1 lukem if ( *filter == NULL ) {
1212 1.1 lukem rc = LDAP_PROTOCOL_ERROR;
1213 1.1 lukem goto done;
1214 1.1 lukem }
1215 1.1 lukem ber_str2bv( ludp->lud_filter, 0, 0, fstr );
1216 1.1 lukem }
1217 1.1 lukem
1218 1.1 lukem /* Grab the searchbase */
1219 1.1 lukem ber_str2bv( ludp->lud_dn, 0, 0, base );
1220 1.1 lukem if ( normalize ) {
1221 1.1 lukem rc = dnNormalize( 0, NULL, NULL, base, nbase, op->o_tmpmemctx );
1222 1.1 lukem } else {
1223 1.1 lukem ber_dupbv_x( nbase, base, op->o_tmpmemctx );
1224 1.1 lukem rc = LDAP_SUCCESS;
1225 1.1 lukem }
1226 1.1 lukem
1227 1.1 lukem done:
1228 1.1 lukem if( rc != LDAP_SUCCESS ) {
1229 1.1 lukem if( *filter ) filter_free_x( op, *filter );
1230 1.1 lukem BER_BVZERO( base );
1231 1.1 lukem BER_BVZERO( fstr );
1232 1.1 lukem } else {
1233 1.1 lukem /* Don't free these, return them to caller */
1234 1.1 lukem ludp->lud_filter = NULL;
1235 1.1 lukem ludp->lud_dn = NULL;
1236 1.1 lukem }
1237 1.1 lukem
1238 1.1 lukem ldap_free_urldesc( ludp );
1239 1.1 lukem return( rc );
1240 1.1 lukem }
1241 1.1 lukem
1242 1.1 lukem #ifndef SLAP_AUTH_REWRITE
1243 1.1 lukem static int slap_sasl_rx_off(char *rep, int *off)
1244 1.1 lukem {
1245 1.1 lukem const char *c;
1246 1.1 lukem int n;
1247 1.1 lukem
1248 1.1 lukem /* Precompile replace pattern. Find the $<n> placeholders */
1249 1.1 lukem off[0] = -2;
1250 1.1 lukem n = 1;
1251 1.1 lukem for ( c = rep; *c; c++ ) {
1252 1.1 lukem if ( *c == '\\' && c[1] ) {
1253 1.1 lukem c++;
1254 1.1 lukem continue;
1255 1.1 lukem }
1256 1.1 lukem if ( *c == '$' ) {
1257 1.1 lukem if ( n == SASLREGEX_REPLACE ) {
1258 1.1 lukem Debug( LDAP_DEBUG_ANY,
1259 1.1 lukem "SASL replace pattern %s has too many $n "
1260 1.1 lukem "placeholders (max %d)\n",
1261 1.1 lukem rep, SASLREGEX_REPLACE, 0 );
1262 1.1 lukem
1263 1.1 lukem return( LDAP_OTHER );
1264 1.1 lukem }
1265 1.1 lukem off[n] = c - rep;
1266 1.1 lukem n++;
1267 1.1 lukem }
1268 1.1 lukem }
1269 1.1 lukem
1270 1.1 lukem /* Final placeholder, after the last $n */
1271 1.1 lukem off[n] = c - rep;
1272 1.1 lukem n++;
1273 1.1 lukem off[n] = -1;
1274 1.1 lukem return( LDAP_SUCCESS );
1275 1.1 lukem }
1276 1.1 lukem #endif /* ! SLAP_AUTH_REWRITE */
1277 1.1 lukem
1278 1.1 lukem #ifdef SLAP_AUTH_REWRITE
1279 1.1 lukem int slap_sasl_rewrite_config(
1280 1.1 lukem const char *fname,
1281 1.1 lukem int lineno,
1282 1.1 lukem int argc,
1283 1.1 lukem char **argv
1284 1.1 lukem )
1285 1.1 lukem {
1286 1.1 lukem int rc;
1287 1.1 lukem char *savearg0;
1288 1.1 lukem
1289 1.1 lukem /* init at first call */
1290 1.1 lukem if ( sasl_rwinfo == NULL ) {
1291 1.1 lukem sasl_rwinfo = rewrite_info_init( REWRITE_MODE_USE_DEFAULT );
1292 1.1 lukem }
1293 1.1 lukem
1294 1.1 lukem /* strip "authid-" prefix for parsing */
1295 1.1 lukem savearg0 = argv[0];
1296 1.1 lukem argv[0] += STRLENOF( "authid-" );
1297 1.1 lukem rc = rewrite_parse( sasl_rwinfo, fname, lineno, argc, argv );
1298 1.1 lukem argv[0] = savearg0;
1299 1.1 lukem
1300 1.1 lukem return rc;
1301 1.1 lukem }
1302 1.1 lukem
1303 1.1 lukem static int
1304 1.1 lukem slap_sasl_rewrite_destroy( void )
1305 1.1 lukem {
1306 1.1 lukem if ( sasl_rwinfo ) {
1307 1.1 lukem rewrite_info_delete( &sasl_rwinfo );
1308 1.1 lukem sasl_rwinfo = NULL;
1309 1.1 lukem }
1310 1.1 lukem
1311 1.1 lukem return 0;
1312 1.1 lukem }
1313 1.1 lukem
1314 1.1 lukem int slap_sasl_regexp_rewrite_config(
1315 1.1 lukem const char *fname,
1316 1.1 lukem int lineno,
1317 1.1 lukem const char *match,
1318 1.1 lukem const char *replace,
1319 1.1 lukem const char *context )
1320 1.1 lukem {
1321 1.1 lukem int rc;
1322 1.1 lukem char *argvRule[] = { "rewriteRule", NULL, NULL, ":@", NULL };
1323 1.1 lukem
1324 1.1 lukem /* init at first call */
1325 1.1 lukem if ( sasl_rwinfo == NULL ) {
1326 1.1 lukem char *argvEngine[] = { "rewriteEngine", "on", NULL };
1327 1.1 lukem char *argvContext[] = { "rewriteContext", NULL, NULL };
1328 1.1 lukem
1329 1.1 lukem /* initialize rewrite engine */
1330 1.1 lukem sasl_rwinfo = rewrite_info_init( REWRITE_MODE_USE_DEFAULT );
1331 1.1 lukem
1332 1.1 lukem /* switch on rewrite engine */
1333 1.1 lukem rc = rewrite_parse( sasl_rwinfo, fname, lineno, 2, argvEngine );
1334 1.1 lukem if (rc != LDAP_SUCCESS) {
1335 1.1 lukem return rc;
1336 1.1 lukem }
1337 1.1 lukem
1338 1.1 lukem /* create generic authid context */
1339 1.1 lukem argvContext[1] = AUTHID_CONTEXT;
1340 1.1 lukem rc = rewrite_parse( sasl_rwinfo, fname, lineno, 2, argvContext );
1341 1.1 lukem if (rc != LDAP_SUCCESS) {
1342 1.1 lukem return rc;
1343 1.1 lukem }
1344 1.1 lukem }
1345 1.1 lukem
1346 1.1 lukem argvRule[1] = (char *)match;
1347 1.1 lukem argvRule[2] = (char *)replace;
1348 1.1 lukem rc = rewrite_parse( sasl_rwinfo, fname, lineno, 4, argvRule );
1349 1.1 lukem
1350 1.1 lukem return rc;
1351 1.1 lukem }
1352 1.1 lukem #endif /* SLAP_AUTH_REWRITE */
1353 1.1 lukem
1354 1.1 lukem int slap_sasl_regexp_config( const char *match, const char *replace )
1355 1.1 lukem {
1356 1.1 lukem int rc;
1357 1.1 lukem SaslRegexp_t *reg;
1358 1.1 lukem
1359 1.1 lukem SaslRegexp = (SaslRegexp_t *) ch_realloc( (char *) SaslRegexp,
1360 1.1 lukem (nSaslRegexp + 1) * sizeof(SaslRegexp_t) );
1361 1.1 lukem
1362 1.1 lukem reg = &SaslRegexp[nSaslRegexp];
1363 1.1 lukem
1364 1.1 lukem #ifdef SLAP_AUTH_REWRITE
1365 1.1 lukem rc = slap_sasl_regexp_rewrite_config( "sasl-regexp", 0,
1366 1.1 lukem match, replace, AUTHID_CONTEXT );
1367 1.1 lukem #else /* ! SLAP_AUTH_REWRITE */
1368 1.1 lukem
1369 1.1 lukem /* Precompile matching pattern */
1370 1.1 lukem rc = regcomp( ®->sr_workspace, match, REG_EXTENDED|REG_ICASE );
1371 1.1 lukem if ( rc ) {
1372 1.1 lukem Debug( LDAP_DEBUG_ANY,
1373 1.1 lukem "SASL match pattern %s could not be compiled by regexp engine\n",
1374 1.1 lukem match, 0, 0 );
1375 1.1 lukem
1376 1.1 lukem #ifdef ENABLE_REWRITE
1377 1.1 lukem /* Dummy block to force symbol references in librewrite */
1378 1.1 lukem if ( slapMode == ( SLAP_SERVER_MODE|SLAP_TOOL_MODE )) {
1379 1.1 lukem rewrite_info_init( 0 );
1380 1.1 lukem }
1381 1.1 lukem #endif
1382 1.1 lukem return( LDAP_OTHER );
1383 1.1 lukem }
1384 1.1 lukem
1385 1.1 lukem rc = slap_sasl_rx_off( replace, reg->sr_offset );
1386 1.1 lukem #endif /* ! SLAP_AUTH_REWRITE */
1387 1.1 lukem if ( rc == LDAP_SUCCESS ) {
1388 1.1 lukem reg->sr_match = ch_strdup( match );
1389 1.1 lukem reg->sr_replace = ch_strdup( replace );
1390 1.1 lukem
1391 1.1 lukem nSaslRegexp++;
1392 1.1 lukem }
1393 1.1 lukem
1394 1.1 lukem return rc;
1395 1.1 lukem }
1396 1.1 lukem
1397 1.1 lukem void
1398 1.1 lukem slap_sasl_regexp_destroy( void )
1399 1.1 lukem {
1400 1.1 lukem if ( SaslRegexp ) {
1401 1.1 lukem int n;
1402 1.1 lukem
1403 1.1 lukem for ( n = 0; n < nSaslRegexp; n++ ) {
1404 1.1 lukem ch_free( SaslRegexp[ n ].sr_match );
1405 1.1 lukem ch_free( SaslRegexp[ n ].sr_replace );
1406 1.1 lukem #ifndef SLAP_AUTH_REWRITE
1407 1.1 lukem regfree( &SaslRegexp[ n ].sr_workspace );
1408 1.1 lukem #endif /* SLAP_AUTH_REWRITE */
1409 1.1 lukem }
1410 1.1 lukem
1411 1.1 lukem ch_free( SaslRegexp );
1412 1.1 lukem }
1413 1.1 lukem
1414 1.1 lukem #ifdef SLAP_AUTH_REWRITE
1415 1.1 lukem slap_sasl_rewrite_destroy();
1416 1.1 lukem #endif /* SLAP_AUTH_REWRITE */
1417 1.1 lukem }
1418 1.1 lukem
1419 1.1 lukem void slap_sasl_regexp_unparse( BerVarray *out )
1420 1.1 lukem {
1421 1.1 lukem int i;
1422 1.1 lukem BerVarray bva = NULL;
1423 1.1 lukem char ibuf[32], *ptr;
1424 1.1 lukem struct berval idx;
1425 1.1 lukem
1426 1.1 lukem if ( !nSaslRegexp ) return;
1427 1.1 lukem
1428 1.1 lukem idx.bv_val = ibuf;
1429 1.1 lukem bva = ch_malloc( (nSaslRegexp+1) * sizeof(struct berval) );
1430 1.1 lukem BER_BVZERO(bva+nSaslRegexp);
1431 1.1 lukem for ( i=0; i<nSaslRegexp; i++ ) {
1432 1.1 lukem idx.bv_len = sprintf( idx.bv_val, "{%d}", i);
1433 1.1 lukem bva[i].bv_len = idx.bv_len + strlen( SaslRegexp[i].sr_match ) +
1434 1.1 lukem strlen( SaslRegexp[i].sr_replace ) + 5;
1435 1.1 lukem bva[i].bv_val = ch_malloc( bva[i].bv_len+1 );
1436 1.1 lukem ptr = lutil_strcopy( bva[i].bv_val, ibuf );
1437 1.1 lukem *ptr++ = '"';
1438 1.1 lukem ptr = lutil_strcopy( ptr, SaslRegexp[i].sr_match );
1439 1.1 lukem ptr = lutil_strcopy( ptr, "\" \"" );
1440 1.1 lukem ptr = lutil_strcopy( ptr, SaslRegexp[i].sr_replace );
1441 1.1 lukem *ptr++ = '"';
1442 1.1 lukem *ptr = '\0';
1443 1.1 lukem }
1444 1.1 lukem *out = bva;
1445 1.1 lukem }
1446 1.1 lukem
1447 1.1 lukem #ifndef SLAP_AUTH_REWRITE
1448 1.1 lukem /* Perform replacement on regexp matches */
1449 1.1 lukem static void slap_sasl_rx_exp(
1450 1.1 lukem const char *rep,
1451 1.1 lukem const int *off,
1452 1.1 lukem regmatch_t *str,
1453 1.1 lukem const char *saslname,
1454 1.1 lukem struct berval *out,
1455 1.1 lukem void *ctx )
1456 1.1 lukem {
1457 1.1 lukem int i, n, len, insert;
1458 1.1 lukem
1459 1.1 lukem /* Get the total length of the final URI */
1460 1.1 lukem
1461 1.1 lukem n=1;
1462 1.1 lukem len = 0;
1463 1.1 lukem while( off[n] >= 0 ) {
1464 1.1 lukem /* Len of next section from replacement string (x,y,z above) */
1465 1.1 lukem len += off[n] - off[n-1] - 2;
1466 1.1 lukem if( off[n+1] < 0)
1467 1.1 lukem break;
1468 1.1 lukem
1469 1.1 lukem /* Len of string from saslname that matched next $i (b,d above) */
1470 1.1 lukem i = rep[ off[n] + 1 ] - '0';
1471 1.1 lukem len += str[i].rm_eo - str[i].rm_so;
1472 1.1 lukem n++;
1473 1.1 lukem }
1474 1.1 lukem out->bv_val = slap_sl_malloc( len + 1, ctx );
1475 1.1 lukem out->bv_len = len;
1476 1.1 lukem
1477 1.1 lukem /* Fill in URI with replace string, replacing $i as we go */
1478 1.1 lukem n=1;
1479 1.1 lukem insert = 0;
1480 1.1 lukem while( off[n] >= 0) {
1481 1.1 lukem /* Paste in next section from replacement string (x,y,z above) */
1482 1.1 lukem len = off[n] - off[n-1] - 2;
1483 1.1 lukem strncpy( out->bv_val+insert, rep + off[n-1] + 2, len);
1484 1.1 lukem insert += len;
1485 1.1 lukem if( off[n+1] < 0)
1486 1.1 lukem break;
1487 1.1 lukem
1488 1.1 lukem /* Paste in string from saslname that matched next $i (b,d above) */
1489 1.1 lukem i = rep[ off[n] + 1 ] - '0';
1490 1.1 lukem len = str[i].rm_eo - str[i].rm_so;
1491 1.1 lukem strncpy( out->bv_val+insert, saslname + str[i].rm_so, len );
1492 1.1 lukem insert += len;
1493 1.1 lukem
1494 1.1 lukem n++;
1495 1.1 lukem }
1496 1.1 lukem
1497 1.1 lukem out->bv_val[insert] = '\0';
1498 1.1 lukem }
1499 1.1 lukem #endif /* ! SLAP_AUTH_REWRITE */
1500 1.1 lukem
1501 1.1 lukem /* Take the passed in SASL name and attempt to convert it into an
1502 1.1 lukem LDAP URI to find the matching LDAP entry, using the pattern matching
1503 1.1 lukem strings given in the saslregexp config file directive(s) */
1504 1.1 lukem
1505 1.1 lukem static int slap_authz_regexp( struct berval *in, struct berval *out,
1506 1.1 lukem int flags, void *ctx )
1507 1.1 lukem {
1508 1.1 lukem #ifdef SLAP_AUTH_REWRITE
1509 1.1 lukem const char *context = AUTHID_CONTEXT;
1510 1.1 lukem
1511 1.1 lukem if ( sasl_rwinfo == NULL || BER_BVISNULL( in ) ) {
1512 1.1 lukem return 0;
1513 1.1 lukem }
1514 1.1 lukem
1515 1.1 lukem /* FIXME: if aware of authc/authz mapping,
1516 1.1 lukem * we could use different contexts ... */
1517 1.1 lukem switch ( rewrite_session( sasl_rwinfo, context, in->bv_val, NULL,
1518 1.1 lukem &out->bv_val ) )
1519 1.1 lukem {
1520 1.1 lukem case REWRITE_REGEXEC_OK:
1521 1.1 lukem if ( !BER_BVISNULL( out ) ) {
1522 1.1 lukem char *val = out->bv_val;
1523 1.1 lukem ber_str2bv_x( val, 0, 1, out, ctx );
1524 1.1 lukem if ( val != in->bv_val ) {
1525 1.1 lukem free( val );
1526 1.1 lukem }
1527 1.1 lukem } else {
1528 1.1 lukem ber_dupbv_x( out, in, ctx );
1529 1.1 lukem }
1530 1.1 lukem Debug( LDAP_DEBUG_ARGS,
1531 1.1 lukem "[rw] %s: \"%s\" -> \"%s\"\n",
1532 1.1 lukem context, in->bv_val, out->bv_val );
1533 1.1 lukem return 1;
1534 1.1 lukem
1535 1.1 lukem case REWRITE_REGEXEC_UNWILLING:
1536 1.1 lukem case REWRITE_REGEXEC_ERR:
1537 1.1 lukem default:
1538 1.1 lukem return 0;
1539 1.1 lukem }
1540 1.1 lukem
1541 1.1 lukem #else /* ! SLAP_AUTH_REWRITE */
1542 1.1 lukem char *saslname = in->bv_val;
1543 1.1 lukem SaslRegexp_t *reg;
1544 1.1 lukem regmatch_t sr_strings[SASLREGEX_REPLACE]; /* strings matching $1,$2 ... */
1545 1.1 lukem int i;
1546 1.1 lukem
1547 1.1 lukem memset( out, 0, sizeof( *out ) );
1548 1.1 lukem
1549 1.1 lukem Debug( LDAP_DEBUG_TRACE, "slap_authz_regexp: converting SASL name %s\n",
1550 1.1 lukem saslname, 0, 0 );
1551 1.1 lukem
1552 1.1 lukem if (( saslname == NULL ) || ( nSaslRegexp == 0 )) {
1553 1.1 lukem return( 0 );
1554 1.1 lukem }
1555 1.1 lukem
1556 1.1 lukem /* Match the normalized SASL name to the saslregexp patterns */
1557 1.1 lukem for( reg = SaslRegexp,i=0; i<nSaslRegexp; i++,reg++ ) {
1558 1.1 lukem if ( regexec( ®->sr_workspace, saslname, SASLREGEX_REPLACE,
1559 1.1 lukem sr_strings, 0) == 0 )
1560 1.1 lukem break;
1561 1.1 lukem }
1562 1.1 lukem
1563 1.1 lukem if( i >= nSaslRegexp ) return( 0 );
1564 1.1 lukem
1565 1.1 lukem /*
1566 1.1 lukem * The match pattern may have been of the form "a(b.*)c(d.*)e" and the
1567 1.1 lukem * replace pattern of the form "x$1y$2z". The returned string needs
1568 1.1 lukem * to replace the $1,$2 with the strings that matched (b.*) and (d.*)
1569 1.1 lukem */
1570 1.1 lukem slap_sasl_rx_exp( reg->sr_replace, reg->sr_offset,
1571 1.1 lukem sr_strings, saslname, out, ctx );
1572 1.1 lukem
1573 1.1 lukem Debug( LDAP_DEBUG_TRACE,
1574 1.1 lukem "slap_authz_regexp: converted SASL name to %s\n",
1575 1.1 lukem BER_BVISEMPTY( out ) ? "" : out->bv_val, 0, 0 );
1576 1.1 lukem
1577 1.1 lukem return( 1 );
1578 1.1 lukem #endif /* ! SLAP_AUTH_REWRITE */
1579 1.1 lukem }
1580 1.1 lukem
1581 1.1 lukem /* This callback actually does some work...*/
1582 1.1 lukem static int sasl_sc_sasl2dn( Operation *op, SlapReply *rs )
1583 1.1 lukem {
1584 1.1 lukem struct berval *ndn = op->o_callback->sc_private;
1585 1.1 lukem
1586 1.1 lukem if ( rs->sr_type != REP_SEARCH ) return LDAP_SUCCESS;
1587 1.1 lukem
1588 1.1 lukem /* We only want to be called once */
1589 1.1 lukem if ( !BER_BVISNULL( ndn ) ) {
1590 1.1 lukem op->o_tmpfree( ndn->bv_val, op->o_tmpmemctx );
1591 1.1 lukem BER_BVZERO( ndn );
1592 1.1 lukem
1593 1.1 lukem Debug( LDAP_DEBUG_TRACE,
1594 1.1 lukem "%s: slap_sc_sasl2dn: search DN returned more than 1 entry\n",
1595 1.1 lukem op->o_log_prefix, 0, 0 );
1596 1.1 lukem return LDAP_UNAVAILABLE; /* short-circuit the search */
1597 1.1 lukem }
1598 1.1 lukem
1599 1.1 lukem ber_dupbv_x( ndn, &rs->sr_entry->e_nname, op->o_tmpmemctx );
1600 1.1 lukem return LDAP_SUCCESS;
1601 1.1 lukem }
1602 1.1 lukem
1603 1.1 lukem
1604 1.1 lukem typedef struct smatch_info {
1605 1.1 lukem struct berval *dn;
1606 1.1 lukem int match;
1607 1.1 lukem } smatch_info;
1608 1.1 lukem
1609 1.1 lukem static int sasl_sc_smatch( Operation *o, SlapReply *rs )
1610 1.1 lukem {
1611 1.1 lukem smatch_info *sm = o->o_callback->sc_private;
1612 1.1 lukem
1613 1.1 lukem if (rs->sr_type != REP_SEARCH) return 0;
1614 1.1 lukem
1615 1.1 lukem if (dn_match(sm->dn, &rs->sr_entry->e_nname)) {
1616 1.1 lukem sm->match = 1;
1617 1.1 lukem return LDAP_UNAVAILABLE; /* short-circuit the search */
1618 1.1 lukem }
1619 1.1 lukem
1620 1.1 lukem return 0;
1621 1.1 lukem }
1622 1.1 lukem
1623 1.1 lukem int
1624 1.1 lukem slap_sasl_matches( Operation *op, BerVarray rules,
1625 1.1 lukem struct berval *assertDN, struct berval *authc )
1626 1.1 lukem {
1627 1.1 lukem int rc = LDAP_INAPPROPRIATE_AUTH;
1628 1.1 lukem
1629 1.1 lukem if ( rules != NULL ) {
1630 1.1 lukem int i;
1631 1.1 lukem
1632 1.1 lukem for( i = 0; !BER_BVISNULL( &rules[i] ); i++ ) {
1633 1.1 lukem rc = slap_sasl_match( op, &rules[i], assertDN, authc );
1634 1.1 lukem if ( rc == LDAP_SUCCESS ) break;
1635 1.1 lukem }
1636 1.1 lukem }
1637 1.1 lukem
1638 1.1 lukem return rc;
1639 1.1 lukem }
1640 1.1 lukem
1641 1.1 lukem /*
1642 1.1 lukem * Map a SASL regexp rule to a DN. If the rule is just a DN or a scope=base
1643 1.1 lukem * URI, just strcmp the rule (or its searchbase) to the *assertDN. Otherwise,
1644 1.1 lukem * the rule must be used as an internal search for entries. If that search
1645 1.1 lukem * returns the *assertDN entry, the match is successful.
1646 1.1 lukem *
1647 1.1 lukem * The assertDN should not have the dn: prefix
1648 1.1 lukem */
1649 1.1 lukem
1650 1.1 lukem static int
1651 1.1 lukem slap_sasl_match( Operation *opx, struct berval *rule,
1652 1.1 lukem struct berval *assertDN, struct berval *authc )
1653 1.1 lukem {
1654 1.1 lukem int rc;
1655 1.1 lukem regex_t reg;
1656 1.1 lukem smatch_info sm;
1657 1.1 lukem slap_callback cb = { NULL, sasl_sc_smatch, NULL, NULL };
1658 1.1 lukem Operation op = {0};
1659 1.1 lukem SlapReply rs = {REP_RESULT};
1660 1.1 lukem struct berval base = BER_BVNULL;
1661 1.1 lukem
1662 1.1 lukem sm.dn = assertDN;
1663 1.1 lukem sm.match = 0;
1664 1.1 lukem cb.sc_private = &sm;
1665 1.1 lukem
1666 1.1 lukem Debug( LDAP_DEBUG_TRACE,
1667 1.1 lukem "===>slap_sasl_match: comparing DN %s to rule %s\n",
1668 1.1 lukem assertDN->bv_len ? assertDN->bv_val : "(null)", rule->bv_val, 0 );
1669 1.1 lukem
1670 1.1 lukem /* NOTE: don't normalize rule if authz syntax is enabled */
1671 1.1 lukem rc = slap_parseURI( opx, rule, &base, &op.o_req_ndn,
1672 1.1 lukem &op.ors_scope, &op.ors_filter, &op.ors_filterstr, 0 );
1673 1.1 lukem
1674 1.1 lukem if( rc != LDAP_SUCCESS ) goto CONCLUDED;
1675 1.1 lukem
1676 1.1 lukem switch ( op.ors_scope ) {
1677 1.1 lukem case LDAP_X_SCOPE_EXACT:
1678 1.1 lukem exact_match:
1679 1.1 lukem if ( dn_match( &op.o_req_ndn, assertDN ) ) {
1680 1.1 lukem rc = LDAP_SUCCESS;
1681 1.1 lukem } else {
1682 1.1 lukem rc = LDAP_INAPPROPRIATE_AUTH;
1683 1.1 lukem }
1684 1.1 lukem goto CONCLUDED;
1685 1.1 lukem
1686 1.1 lukem case LDAP_X_SCOPE_CHILDREN:
1687 1.1 lukem case LDAP_X_SCOPE_SUBTREE:
1688 1.1 lukem case LDAP_X_SCOPE_ONELEVEL:
1689 1.1 lukem {
1690 1.1 lukem int d = assertDN->bv_len - op.o_req_ndn.bv_len;
1691 1.1 lukem
1692 1.1 lukem rc = LDAP_INAPPROPRIATE_AUTH;
1693 1.1 lukem
1694 1.1 lukem if ( d == 0 && op.ors_scope == LDAP_X_SCOPE_SUBTREE ) {
1695 1.1 lukem goto exact_match;
1696 1.1 lukem
1697 1.1 lukem } else if ( d > 0 ) {
1698 1.1 lukem struct berval bv;
1699 1.1 lukem
1700 1.1 lukem /* leave room for at least one char of attributeType,
1701 1.1 lukem * one for '=' and one for ',' */
1702 1.1 lukem if ( d < STRLENOF( "x=,") ) {
1703 1.1 lukem goto CONCLUDED;
1704 1.1 lukem }
1705 1.1 lukem
1706 1.1 lukem bv.bv_len = op.o_req_ndn.bv_len;
1707 1.1 lukem bv.bv_val = assertDN->bv_val + d;
1708 1.1 lukem
1709 1.1 lukem if ( bv.bv_val[ -1 ] == ',' && dn_match( &op.o_req_ndn, &bv ) ) {
1710 1.1 lukem switch ( op.ors_scope ) {
1711 1.1 lukem case LDAP_X_SCOPE_SUBTREE:
1712 1.1 lukem case LDAP_X_SCOPE_CHILDREN:
1713 1.1 lukem rc = LDAP_SUCCESS;
1714 1.1 lukem break;
1715 1.1 lukem
1716 1.1 lukem case LDAP_X_SCOPE_ONELEVEL:
1717 1.1 lukem {
1718 1.1 lukem struct berval pdn;
1719 1.1 lukem
1720 1.1 lukem dnParent( assertDN, &pdn );
1721 1.1 lukem /* the common portion of the DN
1722 1.1 lukem * already matches, so only check
1723 1.1 lukem * if parent DN of assertedDN
1724 1.1 lukem * is all the pattern */
1725 1.1 lukem if ( pdn.bv_len == op.o_req_ndn.bv_len ) {
1726 1.1 lukem rc = LDAP_SUCCESS;
1727 1.1 lukem }
1728 1.1 lukem break;
1729 1.1 lukem }
1730 1.1 lukem default:
1731 1.1 lukem /* at present, impossible */
1732 1.1 lukem assert( 0 );
1733 1.1 lukem }
1734 1.1 lukem }
1735 1.1 lukem }
1736 1.1 lukem goto CONCLUDED;
1737 1.1 lukem }
1738 1.1 lukem
1739 1.1 lukem case LDAP_X_SCOPE_REGEX:
1740 1.1 lukem rc = regcomp(®, op.o_req_ndn.bv_val,
1741 1.1 lukem REG_EXTENDED|REG_ICASE|REG_NOSUB);
1742 1.1 lukem if ( rc == 0 ) {
1743 1.1 lukem rc = regexec(®, assertDN->bv_val, 0, NULL, 0);
1744 1.1 lukem regfree( ® );
1745 1.1 lukem }
1746 1.1 lukem if ( rc == 0 ) {
1747 1.1 lukem rc = LDAP_SUCCESS;
1748 1.1 lukem } else {
1749 1.1 lukem rc = LDAP_INAPPROPRIATE_AUTH;
1750 1.1 lukem }
1751 1.1 lukem goto CONCLUDED;
1752 1.1 lukem
1753 1.1 lukem case LDAP_X_SCOPE_GROUP: {
1754 1.1 lukem char *tmp;
1755 1.1 lukem
1756 1.1 lukem /* Now filterstr looks like "(&(objectClass=<group_oc>)(<member_at>="
1757 1.1 lukem * we need to append the <assertDN> so that the <group_dn> is searched
1758 1.1 lukem * with scope "base", and the filter ensures that <assertDN> is
1759 1.1 lukem * member of the group */
1760 1.1 lukem tmp = ch_realloc( op.ors_filterstr.bv_val, op.ors_filterstr.bv_len +
1761 1.1 lukem assertDN->bv_len + STRLENOF( /*"(("*/ "))" ) + 1 );
1762 1.1 lukem if ( tmp == NULL ) {
1763 1.1 lukem rc = LDAP_NO_MEMORY;
1764 1.1 lukem goto CONCLUDED;
1765 1.1 lukem }
1766 1.1 lukem op.ors_filterstr.bv_val = tmp;
1767 1.1 lukem
1768 1.1 lukem tmp = lutil_strcopy( &tmp[op.ors_filterstr.bv_len], assertDN->bv_val );
1769 1.1 lukem tmp = lutil_strcopy( tmp, /*"(("*/ "))" );
1770 1.1 lukem
1771 1.1 lukem /* pass opx because str2filter_x may (and does) use o_tmpmfuncs */
1772 1.1 lukem op.ors_filter = str2filter_x( opx, op.ors_filterstr.bv_val );
1773 1.1 lukem if ( op.ors_filter == NULL ) {
1774 1.1 lukem rc = LDAP_PROTOCOL_ERROR;
1775 1.1 lukem goto CONCLUDED;
1776 1.1 lukem }
1777 1.1 lukem op.ors_scope = LDAP_SCOPE_BASE;
1778 1.1 lukem
1779 1.1 lukem /* hijack match DN: use that of the group instead of the assertDN;
1780 1.1 lukem * assertDN is now in the filter */
1781 1.1 lukem sm.dn = &op.o_req_ndn;
1782 1.1 lukem
1783 1.1 lukem /* do the search */
1784 1.1 lukem break;
1785 1.1 lukem }
1786 1.1 lukem
1787 1.1 lukem case LDAP_X_SCOPE_USERS:
1788 1.1 lukem if ( !BER_BVISEMPTY( assertDN ) ) {
1789 1.1 lukem rc = LDAP_SUCCESS;
1790 1.1 lukem } else {
1791 1.1 lukem rc = LDAP_INAPPROPRIATE_AUTH;
1792 1.1 lukem }
1793 1.1 lukem goto CONCLUDED;
1794 1.1 lukem
1795 1.1 lukem default:
1796 1.1 lukem break;
1797 1.1 lukem }
1798 1.1 lukem
1799 1.1 lukem /* Must run an internal search. */
1800 1.1 lukem if ( op.ors_filter == NULL ) {
1801 1.1 lukem rc = LDAP_FILTER_ERROR;
1802 1.1 lukem goto CONCLUDED;
1803 1.1 lukem }
1804 1.1 lukem
1805 1.1 lukem Debug( LDAP_DEBUG_TRACE,
1806 1.1 lukem "slap_sasl_match: performing internal search (base=%s, scope=%d)\n",
1807 1.1 lukem op.o_req_ndn.bv_val, op.ors_scope, 0 );
1808 1.1 lukem
1809 1.1 lukem op.o_bd = select_backend( &op.o_req_ndn, 1 );
1810 1.1 lukem if(( op.o_bd == NULL ) || ( op.o_bd->be_search == NULL)) {
1811 1.1 lukem rc = LDAP_INAPPROPRIATE_AUTH;
1812 1.1 lukem goto CONCLUDED;
1813 1.1 lukem }
1814 1.1 lukem
1815 1.1 lukem op.o_hdr = opx->o_hdr;
1816 1.1 lukem op.o_tag = LDAP_REQ_SEARCH;
1817 1.1 lukem op.o_ndn = *authc;
1818 1.1 lukem op.o_callback = &cb;
1819 1.1 lukem slap_op_time( &op.o_time, &op.o_tincr );
1820 1.1 lukem op.o_do_not_cache = 1;
1821 1.1 lukem op.o_is_auth_check = 1;
1822 1.1 lukem /* use req_ndn as req_dn instead of non-pretty base of uri */
1823 1.1 lukem if( !BER_BVISNULL( &base ) ) {
1824 1.1 lukem ch_free( base.bv_val );
1825 1.1 lukem /* just in case... */
1826 1.1 lukem BER_BVZERO( &base );
1827 1.1 lukem }
1828 1.1 lukem ber_dupbv_x( &op.o_req_dn, &op.o_req_ndn, op.o_tmpmemctx );
1829 1.1 lukem op.ors_deref = LDAP_DEREF_NEVER;
1830 1.1 lukem op.ors_slimit = 1;
1831 1.1 lukem op.ors_tlimit = SLAP_NO_LIMIT;
1832 1.1 lukem op.ors_attrs = slap_anlist_no_attrs;
1833 1.1 lukem op.ors_attrsonly = 1;
1834 1.1 lukem
1835 1.1 lukem op.o_bd->be_search( &op, &rs );
1836 1.1 lukem
1837 1.1 lukem if (sm.match) {
1838 1.1 lukem rc = LDAP_SUCCESS;
1839 1.1 lukem } else {
1840 1.1 lukem rc = LDAP_INAPPROPRIATE_AUTH;
1841 1.1 lukem }
1842 1.1 lukem
1843 1.1 lukem CONCLUDED:
1844 1.1 lukem if( !BER_BVISNULL( &op.o_req_dn ) ) slap_sl_free( op.o_req_dn.bv_val, opx->o_tmpmemctx );
1845 1.1 lukem if( !BER_BVISNULL( &op.o_req_ndn ) ) slap_sl_free( op.o_req_ndn.bv_val, opx->o_tmpmemctx );
1846 1.1 lukem if( op.ors_filter ) filter_free_x( opx, op.ors_filter );
1847 1.1 lukem if( !BER_BVISNULL( &op.ors_filterstr ) ) ch_free( op.ors_filterstr.bv_val );
1848 1.1 lukem
1849 1.1 lukem Debug( LDAP_DEBUG_TRACE,
1850 1.1 lukem "<===slap_sasl_match: comparison returned %d\n", rc, 0, 0);
1851 1.1 lukem
1852 1.1 lukem return( rc );
1853 1.1 lukem }
1854 1.1 lukem
1855 1.1 lukem
1856 1.1 lukem /*
1857 1.1 lukem * This function answers the question, "Can this ID authorize to that ID?",
1858 1.1 lukem * based on authorization rules. The rules are stored in the *searchDN, in the
1859 1.1 lukem * attribute named by *attr. If any of those rules map to the *assertDN, the
1860 1.1 lukem * authorization is approved.
1861 1.1 lukem *
1862 1.1 lukem * The DNs should not have the dn: prefix
1863 1.1 lukem */
1864 1.1 lukem static int
1865 1.1 lukem slap_sasl_check_authz( Operation *op,
1866 1.1 lukem struct berval *searchDN,
1867 1.1 lukem struct berval *assertDN,
1868 1.1 lukem AttributeDescription *ad,
1869 1.1 lukem struct berval *authc )
1870 1.1 lukem {
1871 1.1 lukem int rc,
1872 1.1 lukem do_not_cache = op->o_do_not_cache;
1873 1.1 lukem BerVarray vals = NULL;
1874 1.1 lukem
1875 1.1 lukem Debug( LDAP_DEBUG_TRACE,
1876 1.1 lukem "==>slap_sasl_check_authz: does %s match %s rule in %s?\n",
1877 1.1 lukem assertDN->bv_val, ad->ad_cname.bv_val, searchDN->bv_val);
1878 1.1 lukem
1879 1.1 lukem /* ITS#4760: don't cache group access */
1880 1.1 lukem op->o_do_not_cache = 1;
1881 1.1 lukem rc = backend_attribute( op, NULL, searchDN, ad, &vals, ACL_AUTH );
1882 1.1 lukem op->o_do_not_cache = do_not_cache;
1883 1.1 lukem if( rc != LDAP_SUCCESS ) goto COMPLETE;
1884 1.1 lukem
1885 1.1 lukem /* Check if the *assertDN matches any *vals */
1886 1.1 lukem rc = slap_sasl_matches( op, vals, assertDN, authc );
1887 1.1 lukem
1888 1.1 lukem COMPLETE:
1889 1.1 lukem if( vals ) ber_bvarray_free_x( vals, op->o_tmpmemctx );
1890 1.1 lukem
1891 1.1 lukem Debug( LDAP_DEBUG_TRACE,
1892 1.1 lukem "<==slap_sasl_check_authz: %s check returning %d\n",
1893 1.1 lukem ad->ad_cname.bv_val, rc, 0);
1894 1.1 lukem
1895 1.1 lukem return( rc );
1896 1.1 lukem }
1897 1.1 lukem
1898 1.1 lukem /*
1899 1.1 lukem * Given a SASL name (e.g. "UID=name,cn=REALM,cn=MECH,cn=AUTH")
1900 1.1 lukem * return the LDAP DN to which it matches. The SASL regexp rules in the config
1901 1.1 lukem * file turn the SASL name into an LDAP URI. If the URI is just a DN (or a
1902 1.1 lukem * search with scope=base), just return the URI (or its searchbase). Otherwise
1903 1.1 lukem * an internal search must be done, and if that search returns exactly one
1904 1.1 lukem * entry, return the DN of that one entry.
1905 1.1 lukem */
1906 1.1 lukem void
1907 1.1 lukem slap_sasl2dn(
1908 1.1 lukem Operation *opx,
1909 1.1 lukem struct berval *saslname,
1910 1.1 lukem struct berval *sasldn,
1911 1.1 lukem int flags )
1912 1.1 lukem {
1913 1.1 lukem int rc;
1914 1.1 lukem slap_callback cb = { NULL, sasl_sc_sasl2dn, NULL, NULL };
1915 1.1 lukem Operation op = {0};
1916 1.1 lukem SlapReply rs = {REP_RESULT};
1917 1.1 lukem struct berval regout = BER_BVNULL;
1918 1.1 lukem struct berval base = BER_BVNULL;
1919 1.1 lukem
1920 1.1 lukem Debug( LDAP_DEBUG_TRACE, "==>slap_sasl2dn: "
1921 1.1 lukem "converting SASL name %s to a DN\n",
1922 1.1 lukem saslname->bv_val, 0,0 );
1923 1.1 lukem
1924 1.1 lukem BER_BVZERO( sasldn );
1925 1.1 lukem cb.sc_private = sasldn;
1926 1.1 lukem
1927 1.1 lukem /* Convert the SASL name into a minimal URI */
1928 1.1 lukem if( !slap_authz_regexp( saslname, ®out, flags, opx->o_tmpmemctx ) ) {
1929 1.1 lukem goto FINISHED;
1930 1.1 lukem }
1931 1.1 lukem
1932 1.1 lukem /* NOTE: always normalize regout because it results
1933 1.1 lukem * from string submatch expansion */
1934 1.1 lukem rc = slap_parseURI( opx, ®out, &base, &op.o_req_ndn,
1935 1.1 lukem &op.ors_scope, &op.ors_filter, &op.ors_filterstr, 1 );
1936 1.1 lukem if ( !BER_BVISNULL( ®out ) ) slap_sl_free( regout.bv_val, opx->o_tmpmemctx );
1937 1.1 lukem if ( rc != LDAP_SUCCESS ) {
1938 1.1 lukem goto FINISHED;
1939 1.1 lukem }
1940 1.1 lukem
1941 1.1 lukem /* Must do an internal search */
1942 1.1 lukem op.o_bd = select_backend( &op.o_req_ndn, 1 );
1943 1.1 lukem
1944 1.1 lukem switch ( op.ors_scope ) {
1945 1.1 lukem case LDAP_X_SCOPE_EXACT:
1946 1.1 lukem *sasldn = op.o_req_ndn;
1947 1.1 lukem BER_BVZERO( &op.o_req_ndn );
1948 1.1 lukem /* intentionally continue to next case */
1949 1.1 lukem
1950 1.1 lukem case LDAP_X_SCOPE_REGEX:
1951 1.1 lukem case LDAP_X_SCOPE_SUBTREE:
1952 1.1 lukem case LDAP_X_SCOPE_CHILDREN:
1953 1.1 lukem case LDAP_X_SCOPE_ONELEVEL:
1954 1.1 lukem case LDAP_X_SCOPE_GROUP:
1955 1.1 lukem case LDAP_X_SCOPE_USERS:
1956 1.1 lukem /* correctly parsed, but illegal */
1957 1.1 lukem goto FINISHED;
1958 1.1 lukem
1959 1.1 lukem case LDAP_SCOPE_BASE:
1960 1.1 lukem case LDAP_SCOPE_ONELEVEL:
1961 1.1 lukem case LDAP_SCOPE_SUBTREE:
1962 1.1 lukem case LDAP_SCOPE_SUBORDINATE:
1963 1.1 lukem /* do a search */
1964 1.1 lukem break;
1965 1.1 lukem
1966 1.1 lukem default:
1967 1.1 lukem /* catch unhandled cases (there shouldn't be) */
1968 1.1 lukem assert( 0 );
1969 1.1 lukem }
1970 1.1 lukem
1971 1.1 lukem Debug( LDAP_DEBUG_TRACE,
1972 1.1 lukem "slap_sasl2dn: performing internal search (base=%s, scope=%d)\n",
1973 1.1 lukem op.o_req_ndn.bv_val, op.ors_scope, 0 );
1974 1.1 lukem
1975 1.1 lukem if ( ( op.o_bd == NULL ) || ( op.o_bd->be_search == NULL) ) {
1976 1.1 lukem goto FINISHED;
1977 1.1 lukem }
1978 1.1 lukem
1979 1.1 lukem /* Must run an internal search. */
1980 1.1 lukem if ( op.ors_filter == NULL ) {
1981 1.1 lukem rc = LDAP_FILTER_ERROR;
1982 1.1 lukem goto FINISHED;
1983 1.1 lukem }
1984 1.1 lukem
1985 1.1 lukem op.o_hdr = opx->o_hdr;
1986 1.1 lukem op.o_tag = LDAP_REQ_SEARCH;
1987 1.1 lukem op.o_ndn = opx->o_conn->c_ndn;
1988 1.1 lukem op.o_callback = &cb;
1989 1.1 lukem slap_op_time( &op.o_time, &op.o_tincr );
1990 1.1 lukem op.o_do_not_cache = 1;
1991 1.1 lukem op.o_is_auth_check = 1;
1992 1.1 lukem op.ors_deref = LDAP_DEREF_NEVER;
1993 1.1 lukem op.ors_slimit = 1;
1994 1.1 lukem op.ors_tlimit = SLAP_NO_LIMIT;
1995 1.1 lukem op.ors_attrs = slap_anlist_no_attrs;
1996 1.1 lukem op.ors_attrsonly = 1;
1997 1.1 lukem /* use req_ndn as req_dn instead of non-pretty base of uri */
1998 1.1 lukem if( !BER_BVISNULL( &base ) ) {
1999 1.1 lukem ch_free( base.bv_val );
2000 1.1 lukem /* just in case... */
2001 1.1 lukem BER_BVZERO( &base );
2002 1.1 lukem }
2003 1.1 lukem ber_dupbv_x( &op.o_req_dn, &op.o_req_ndn, op.o_tmpmemctx );
2004 1.1 lukem
2005 1.1 lukem op.o_bd->be_search( &op, &rs );
2006 1.1 lukem
2007 1.1 lukem FINISHED:
2008 1.1 lukem if( !BER_BVISEMPTY( sasldn ) ) {
2009 1.1 lukem opx->o_conn->c_authz_backend = op.o_bd;
2010 1.1 lukem }
2011 1.1 lukem if( !BER_BVISNULL( &op.o_req_dn ) ) {
2012 1.1 lukem slap_sl_free( op.o_req_dn.bv_val, opx->o_tmpmemctx );
2013 1.1 lukem }
2014 1.1 lukem if( !BER_BVISNULL( &op.o_req_ndn ) ) {
2015 1.1 lukem slap_sl_free( op.o_req_ndn.bv_val, opx->o_tmpmemctx );
2016 1.1 lukem }
2017 1.1 lukem if( op.ors_filter ) {
2018 1.1 lukem filter_free_x( opx, op.ors_filter );
2019 1.1 lukem }
2020 1.1 lukem if( !BER_BVISNULL( &op.ors_filterstr ) ) {
2021 1.1 lukem ch_free( op.ors_filterstr.bv_val );
2022 1.1 lukem }
2023 1.1 lukem
2024 1.1 lukem Debug( LDAP_DEBUG_TRACE, "<==slap_sasl2dn: Converted SASL name to %s\n",
2025 1.1 lukem !BER_BVISEMPTY( sasldn ) ? sasldn->bv_val : "<nothing>", 0, 0 );
2026 1.1 lukem
2027 1.1 lukem return;
2028 1.1 lukem }
2029 1.1 lukem
2030 1.1 lukem
2031 1.1 lukem /* Check if a bind can SASL authorize to another identity.
2032 1.1 lukem * The DNs should not have the dn: prefix
2033 1.1 lukem */
2034 1.1 lukem
2035 1.1 lukem int slap_sasl_authorized( Operation *op,
2036 1.1 lukem struct berval *authcDN, struct berval *authzDN )
2037 1.1 lukem {
2038 1.1 lukem int rc = LDAP_INAPPROPRIATE_AUTH;
2039 1.1 lukem
2040 1.1 lukem /* User binding as anonymous */
2041 1.1 lukem if ( !authzDN || !authzDN->bv_len || !authzDN->bv_val ) {
2042 1.1 lukem rc = LDAP_SUCCESS;
2043 1.1 lukem goto DONE;
2044 1.1 lukem }
2045 1.1 lukem
2046 1.1 lukem /* User is anonymous */
2047 1.1 lukem if ( !authcDN || !authcDN->bv_len || !authcDN->bv_val ) {
2048 1.1 lukem goto DONE;
2049 1.1 lukem }
2050 1.1 lukem
2051 1.1 lukem Debug( LDAP_DEBUG_TRACE,
2052 1.1 lukem "==>slap_sasl_authorized: can %s become %s?\n",
2053 1.1 lukem authcDN->bv_len ? authcDN->bv_val : "(null)",
2054 1.1 lukem authzDN->bv_len ? authzDN->bv_val : "(null)", 0 );
2055 1.1 lukem
2056 1.1 lukem /* If person is authorizing to self, succeed */
2057 1.1 lukem if ( dn_match( authcDN, authzDN ) ) {
2058 1.1 lukem rc = LDAP_SUCCESS;
2059 1.1 lukem goto DONE;
2060 1.1 lukem }
2061 1.1 lukem
2062 1.1 lukem /* Allow the manager to authorize as any DN. */
2063 1.1 lukem if( op->o_conn->c_authz_backend &&
2064 1.1 lukem be_isroot_dn( op->o_conn->c_authz_backend, authcDN ))
2065 1.1 lukem {
2066 1.1 lukem rc = LDAP_SUCCESS;
2067 1.1 lukem goto DONE;
2068 1.1 lukem }
2069 1.1 lukem
2070 1.1 lukem /* Check source rules */
2071 1.1 lukem if( authz_policy & SASL_AUTHZ_TO ) {
2072 1.1 lukem rc = slap_sasl_check_authz( op, authcDN, authzDN,
2073 1.1 lukem slap_schema.si_ad_saslAuthzTo, authcDN );
2074 1.1 lukem if( rc == LDAP_SUCCESS && !(authz_policy & SASL_AUTHZ_AND) ) {
2075 1.1 lukem goto DONE;
2076 1.1 lukem }
2077 1.1 lukem }
2078 1.1 lukem
2079 1.1 lukem /* Check destination rules */
2080 1.1 lukem if( authz_policy & SASL_AUTHZ_FROM ) {
2081 1.1 lukem rc = slap_sasl_check_authz( op, authzDN, authcDN,
2082 1.1 lukem slap_schema.si_ad_saslAuthzFrom, authcDN );
2083 1.1 lukem if( rc == LDAP_SUCCESS ) {
2084 1.1 lukem goto DONE;
2085 1.1 lukem }
2086 1.1 lukem }
2087 1.1 lukem
2088 1.1 lukem rc = LDAP_INAPPROPRIATE_AUTH;
2089 1.1 lukem
2090 1.1 lukem DONE:
2091 1.1 lukem
2092 1.1 lukem Debug( LDAP_DEBUG_TRACE,
2093 1.1 lukem "<== slap_sasl_authorized: return %d\n", rc, 0, 0 );
2094 1.1 lukem
2095 1.1 lukem return( rc );
2096 1.1 lukem }
2097