]> git.sur5r.net Git - openldap/blob - contrib/slapd-modules/acl/gssacl.c
Merge remote-tracking branch 'origin/mdb.RE/0.9' into OPENLDAP_REL_ENG_2_4
[openldap] / contrib / slapd-modules / acl / gssacl.c
1 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
2  *
3  * Copyright 2011 PADL Software Pty Ltd.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted only as authorized by the OpenLDAP
8  * Public License.
9  *
10  * A copy of this license is available in the file LICENSE in the
11  * top-level directory of the distribution or, alternatively, at
12  * <http://www.OpenLDAP.org/license.html>.
13  */
14
15 #include <portable.h>
16
17 #include <ac/string.h>
18 #include <slap.h>
19 #include <lutil.h>
20
21 #include <sasl/sasl.h>
22 #include <gssapi/gssapi.h>
23 #include <gssapi/gssapi_ext.h>
24
25 #define ACL_BUF_SIZE 1024
26
27 typedef struct gssattr_t {
28         slap_style_t            gssattr_style;
29         struct berval           gssattr_name;           /* asserted name */
30         struct berval           gssattr_value;          /* asserted value */
31 } gssattr_t;
32
33 static int gssattr_dynacl_destroy( void *priv );
34
35 static int
36 regex_matches(
37         struct berval   *pat,           /* pattern to expand and match against */
38         char            *str,           /* string to match against pattern */
39         struct berval   *dn_matches,    /* buffer with $N expansion variables from DN */
40         struct berval   *val_matches,   /* buffer with $N expansion variables from val */
41         AclRegexMatches *matches        /* offsets in buffer for $N expansion variables */
42 );
43
44 static int
45 gssattr_dynacl_parse(
46         const char      *fname,
47         int             lineno,
48         const char      *opts,
49         slap_style_t    style,
50         const char      *pattern,
51         void            **privp )
52 {
53         gssattr_t       *gssattr;
54
55         gssattr = (gssattr_t *)ch_calloc( 1, sizeof( gssattr_t ) );
56
57         if ( opts == NULL || opts[0] == '\0' ) {
58                 fprintf( stderr, "%s line %d: GSS ACL: no attribute specified.\n",
59                          fname, lineno );
60                 goto cleanup;
61         }
62
63         if ( pattern == NULL || pattern[0] == '\0' ) {
64                 fprintf( stderr, "%s line %d: GSS ACL: no attribute value specified.\n",
65                          fname, lineno );
66                 goto cleanup;
67         }
68
69         gssattr->gssattr_style = style;
70
71         switch ( gssattr->gssattr_style ) {
72         case ACL_STYLE_BASE:
73         case ACL_STYLE_REGEX:
74         case ACL_STYLE_EXPAND:
75                 break;
76         default:
77                 fprintf( stderr, "%s line %d: GSS ACL: unsupported style \"%s\".\n",
78                          fname, lineno, style_strings[style] );
79                 goto cleanup;
80                 break;
81         }
82
83         ber_str2bv( opts,    0, 1, &gssattr->gssattr_name );
84         ber_str2bv( pattern, 0, 1, &gssattr->gssattr_value );
85
86         *privp = (void *)gssattr;
87         return 0;
88
89 cleanup:
90         (void)gssattr_dynacl_destroy( (void *)gssattr );
91
92         return 1;
93 }
94
95 static int
96 gssattr_dynacl_unparse(
97         void            *priv,
98         struct berval   *bv )
99 {
100         gssattr_t       *gssattr = (gssattr_t *)priv;
101         char            *ptr;
102
103         bv->bv_len = STRLENOF( " dynacl/gss/.expand=" ) +
104                      gssattr->gssattr_name.bv_len +
105                      gssattr->gssattr_value.bv_len;
106         bv->bv_val = ch_malloc( bv->bv_len + 1 );
107
108         ptr = lutil_strcopy( bv->bv_val, " dynacl/gss/" );
109         ptr = lutil_strncopy( ptr, gssattr->gssattr_name.bv_val,
110                               gssattr->gssattr_name.bv_len );
111         switch ( gssattr->gssattr_style ) {
112         case ACL_STYLE_BASE:
113                 ptr = lutil_strcopy( ptr, ".exact=" );
114                 break;
115         case ACL_STYLE_REGEX:
116                 ptr = lutil_strcopy( ptr, ".regex=" );
117                 break;
118         case ACL_STYLE_EXPAND:
119                 ptr = lutil_strcopy( ptr, ".expand=" );
120                 break;
121         default:
122                 assert( 0 );
123                 break;
124         }
125
126         ptr = lutil_strncopy( ptr, gssattr->gssattr_value.bv_val,
127                               gssattr->gssattr_value.bv_len );
128
129         ptr[ 0 ] = '\0';
130
131         bv->bv_len = ptr - bv->bv_val;
132
133         return 0;
134 }
135
136 static int
137 gssattr_dynacl_mask(
138         void                    *priv,
139         Operation               *op,
140         Entry                   *target,
141         AttributeDescription    *desc,
142         struct berval           *val,
143         int                     nmatch,
144         regmatch_t              *matches,
145         slap_access_t           *grant,
146         slap_access_t           *deny )
147 {
148         gssattr_t       *gssattr = (gssattr_t *)priv;
149         sasl_conn_t     *sasl_ctx = op->o_conn->c_sasl_authctx;
150         gss_name_t      gss_name = GSS_C_NO_NAME;
151         OM_uint32       major, minor;
152         int             more = -1;
153         int             authenticated, complete;
154         gss_buffer_desc attr = GSS_C_EMPTY_BUFFER;
155         int             granted = 0;
156
157         ACL_INVALIDATE( *deny );
158
159         if ( sasl_ctx == NULL ||
160              sasl_getprop( sasl_ctx, SASL_GSS_PEER_NAME, (const void **)&gss_name) != 0 ||
161              gss_name == GSS_C_NO_NAME ) {
162                 return 0;
163         }
164
165         attr.length = gssattr->gssattr_name.bv_len;
166         attr.value = gssattr->gssattr_name.bv_val;
167
168         while ( more != 0 ) {
169                 AclRegexMatches amatches = { 0 };
170                 gss_buffer_desc gss_value = GSS_C_EMPTY_BUFFER;
171                 gss_buffer_desc gss_display_value = GSS_C_EMPTY_BUFFER;
172                 struct berval bv_value;
173
174                 major = gss_get_name_attribute( &minor, gss_name, &attr,
175                                                 &authenticated, &complete,
176                                                 &gss_value, &gss_display_value, &more );
177                 if ( GSS_ERROR( major ) ) {
178                         break;
179                 } else if ( authenticated == 0 ) {
180                         gss_release_buffer( &minor, &gss_value );
181                         gss_release_buffer( &minor, &gss_display_value );
182                         continue;
183                 }
184
185                 bv_value.bv_len = gss_value.length;
186                 bv_value.bv_val = (char *)gss_value.value;
187
188                 if ( !ber_bvccmp( &gssattr->gssattr_value, '*' ) ) {
189                         if ( gssattr->gssattr_style != ACL_STYLE_BASE ) {
190                                 amatches.dn_count = nmatch;
191                                 AC_MEMCPY( amatches.dn_data, matches, sizeof( amatches.dn_data ) );
192                         }
193
194                         switch ( gssattr->gssattr_style ) {
195                         case ACL_STYLE_REGEX:
196                                 /* XXX assumes value NUL terminated */
197                                 granted = regex_matches( &gssattr->gssattr_value, bv_value.bv_val,
198                                                           &target->e_nname, val, &amatches );
199                                 break;
200                         case ACL_STYLE_EXPAND: {
201                                 struct berval bv;
202                                 char buf[ACL_BUF_SIZE];
203
204                                 bv.bv_len = sizeof( buf ) - 1;
205                                 bv.bv_val = buf;
206
207                                 granted = ( acl_string_expand( &bv, &gssattr->gssattr_value,
208                                                                &target->e_nname, val,
209                                                                &amatches ) == 0 ) &&
210                                           ( ber_bvstrcmp( &bv, &bv_value) == 0 );
211                                 break;
212                         }
213                         case ACL_STYLE_BASE:
214                                 granted = ( ber_bvstrcmp( &gssattr->gssattr_value, &bv_value ) == 0 );
215                                 break;
216                         default:
217                                 assert(0);
218                                 break;
219                         }
220                 } else {
221                         granted = 1;
222                 }
223
224                 gss_release_buffer( &minor, &gss_value );
225                 gss_release_buffer( &minor, &gss_display_value );
226
227                 if ( granted ) {
228                         break;
229                 }
230         }
231
232         if ( granted ) {
233                 ACL_LVL_ASSIGN_WRITE( *grant );
234         }
235
236         return 0;
237 }
238
239 static int
240 gssattr_dynacl_destroy(
241         void            *priv )
242 {
243         gssattr_t               *gssattr = (gssattr_t *)priv;
244
245         if ( gssattr != NULL ) {
246                 if ( !BER_BVISNULL( &gssattr->gssattr_name ) ) {
247                         ber_memfree( gssattr->gssattr_name.bv_val );
248                 }
249                 if ( !BER_BVISNULL( &gssattr->gssattr_value ) ) {
250                         ber_memfree( gssattr->gssattr_value.bv_val );
251                 }
252                 ch_free( gssattr );
253         }
254
255         return 0;
256 }
257
258 static struct slap_dynacl_t gssattr_dynacl = {
259         "gss",
260         gssattr_dynacl_parse,
261         gssattr_dynacl_unparse,
262         gssattr_dynacl_mask,
263         gssattr_dynacl_destroy
264 };
265
266 int
267 init_module( int argc, char *argv[] )
268 {
269         return slap_dynacl_register( &gssattr_dynacl );
270 }
271
272
273 static int
274 regex_matches(
275         struct berval   *pat,           /* pattern to expand and match against */
276         char            *str,           /* string to match against pattern */
277         struct berval   *dn_matches,    /* buffer with $N expansion variables from DN */
278         struct berval   *val_matches,   /* buffer with $N expansion variables from val */
279         AclRegexMatches *matches        /* offsets in buffer for $N expansion variables */
280 )
281 {
282         regex_t re;
283         char newbuf[ACL_BUF_SIZE];
284         struct berval bv;
285         int     rc;
286
287         bv.bv_len = sizeof( newbuf ) - 1;
288         bv.bv_val = newbuf;
289
290         if (str == NULL) {
291                 str = "";
292         };
293
294         acl_string_expand( &bv, pat, dn_matches, val_matches, matches );
295         rc = regcomp( &re, newbuf, REG_EXTENDED|REG_ICASE );
296         if ( rc ) {
297                 char error[ACL_BUF_SIZE];
298                 regerror( rc, &re, error, sizeof( error ) );
299
300                 Debug( LDAP_DEBUG_TRACE,
301                     "compile( \"%s\", \"%s\") failed %s\n",
302                         pat->bv_val, str, error );
303                 return( 0 );
304         }
305
306         rc = regexec( &re, str, 0, NULL, 0 );
307         regfree( &re );
308
309         Debug( LDAP_DEBUG_TRACE,
310             "=> regex_matches: string:   %s\n", str, 0, 0 );
311         Debug( LDAP_DEBUG_TRACE,
312             "=> regex_matches: rc: %d %s\n",
313                 rc, !rc ? "matches" : "no matches", 0 );
314         return( !rc );
315 }
316