Back to index

openldap  2.4.31
gssacl.c
Go to the documentation of this file.
00001 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00002  *
00003  * Copyright 2011 PADL Software Pty Ltd.
00004  * All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted only as authorized by the OpenLDAP
00008  * Public License.
00009  *
00010  * A copy of this license is available in the file LICENSE in the
00011  * top-level directory of the distribution or, alternatively, at
00012  * <http://www.OpenLDAP.org/license.html>.
00013  */
00014 
00015 #include <portable.h>
00016 
00017 #include <ac/string.h>
00018 #include <slap.h>
00019 #include <lutil.h>
00020 
00021 #include <sasl/sasl.h>
00022 #include <gssapi/gssapi.h>
00023 #include <gssapi/gssapi_ext.h>
00024 
00025 #define ACL_BUF_SIZE 1024
00026 
00027 typedef struct gssattr_t {
00028        slap_style_t         gssattr_style;
00029        struct berval        gssattr_name;        /* asserted name */
00030        struct berval        gssattr_value;              /* asserted value */
00031 } gssattr_t;
00032 
00033 static int gssattr_dynacl_destroy( void *priv );
00034 
00035 static int
00036 regex_matches(
00037        struct berval *pat,         /* pattern to expand and match against */
00038        char          *str,         /* string to match against pattern */
00039        struct berval *dn_matches,  /* buffer with $N expansion variables from DN */
00040        struct berval *val_matches, /* buffer with $N expansion variables from val */
00041        AclRegexMatches      *matches      /* offsets in buffer for $N expansion variables */
00042 );
00043 
00044 static int
00045 gssattr_dynacl_parse(
00046        const char    *fname,
00047        int           lineno,
00048        const char    *opts,
00049        slap_style_t  style,
00050        const char    *pattern,
00051        void          **privp )
00052 {
00053        gssattr_t     *gssattr;
00054 
00055        gssattr = (gssattr_t *)ch_calloc( 1, sizeof( gssattr_t ) );
00056 
00057        if ( opts == NULL || opts[0] == '\0' ) {
00058               fprintf( stderr, "%s line %d: GSS ACL: no attribute specified.\n",
00059                       fname, lineno );
00060               goto cleanup;
00061        }
00062 
00063        if ( pattern == NULL || pattern[0] == '\0' ) {
00064               fprintf( stderr, "%s line %d: GSS ACL: no attribute value specified.\n",
00065                       fname, lineno );
00066               goto cleanup;
00067        }
00068 
00069        gssattr->gssattr_style = style;
00070 
00071        switch ( gssattr->gssattr_style ) {
00072        case ACL_STYLE_BASE:
00073        case ACL_STYLE_REGEX:
00074        case ACL_STYLE_EXPAND:
00075               break;
00076        default:
00077               fprintf( stderr, "%s line %d: GSS ACL: unsupported style \"%s\".\n",
00078                       fname, lineno, style_strings[style] );
00079               goto cleanup;
00080               break;
00081        }
00082 
00083        ber_str2bv( opts,    0, 1, &gssattr->gssattr_name );
00084        ber_str2bv( pattern, 0, 1, &gssattr->gssattr_value );
00085 
00086        *privp = (void *)gssattr;
00087        return 0;
00088 
00089 cleanup:
00090        (void)gssattr_dynacl_destroy( (void *)gssattr );
00091 
00092        return 1;
00093 }
00094 
00095 static int
00096 gssattr_dynacl_unparse(
00097        void          *priv,
00098        struct berval *bv )
00099 {
00100        gssattr_t     *gssattr = (gssattr_t *)priv;
00101        char          *ptr;
00102 
00103        bv->bv_len = STRLENOF( " dynacl/gss/.expand=" ) +
00104                    gssattr->gssattr_name.bv_len +
00105                    gssattr->gssattr_value.bv_len;
00106        bv->bv_val = ch_malloc( bv->bv_len + 1 );
00107 
00108        ptr = lutil_strcopy( bv->bv_val, " dynacl/gss/" );
00109        ptr = lutil_strncopy( ptr, gssattr->gssattr_name.bv_val,
00110                            gssattr->gssattr_name.bv_len );
00111        switch ( gssattr->gssattr_style ) {
00112        case ACL_STYLE_BASE:
00113               ptr = lutil_strcopy( ptr, ".exact=" );
00114               break;
00115        case ACL_STYLE_REGEX:
00116               ptr = lutil_strcopy( ptr, ".regex=" );
00117               break;
00118        case ACL_STYLE_EXPAND:
00119               ptr = lutil_strcopy( ptr, ".expand=" );
00120               break;
00121        default:
00122               assert( 0 );
00123               break;
00124        }
00125 
00126        ptr = lutil_strncopy( ptr, gssattr->gssattr_value.bv_val,
00127                            gssattr->gssattr_value.bv_len );
00128 
00129        ptr[ 0 ] = '\0';
00130 
00131        bv->bv_len = ptr - bv->bv_val;
00132 
00133        return 0;
00134 }
00135 
00136 static int
00137 gssattr_dynacl_mask(
00138        void                 *priv,
00139        Operation            *op,
00140        Entry                *target,
00141        AttributeDescription *desc,
00142        struct berval        *val,
00143        int                  nmatch,
00144        regmatch_t           *matches,
00145        slap_access_t        *grant,
00146        slap_access_t        *deny )
00147 {
00148        gssattr_t     *gssattr = (gssattr_t *)priv;
00149        sasl_conn_t   *sasl_ctx = op->o_conn->c_sasl_authctx;
00150        gss_name_t    gss_name = GSS_C_NO_NAME;
00151        OM_uint32     major, minor;
00152        int           more = -1;
00153        int           authenticated, complete;
00154        gss_buffer_desc      attr = GSS_C_EMPTY_BUFFER;
00155        int           granted = 0;
00156 
00157        ACL_INVALIDATE( *deny );
00158 
00159        if ( sasl_ctx == NULL ||
00160             sasl_getprop( sasl_ctx, SASL_GSS_PEER_NAME, (const void **)&gss_name) != 0 ||
00161             gss_name == GSS_C_NO_NAME ) {
00162               return 0;
00163        }
00164 
00165        attr.length = gssattr->gssattr_name.bv_len;
00166        attr.value = gssattr->gssattr_name.bv_val;
00167 
00168        while ( more != 0 ) {
00169               AclRegexMatches amatches = { 0 };
00170               gss_buffer_desc      gss_value = GSS_C_EMPTY_BUFFER;
00171               gss_buffer_desc      gss_display_value = GSS_C_EMPTY_BUFFER;
00172               struct berval bv_value;
00173 
00174               major = gss_get_name_attribute( &minor, gss_name, &attr,
00175                                           &authenticated, &complete,
00176                                           &gss_value, &gss_display_value, &more );
00177               if ( GSS_ERROR( major ) ) {
00178                      break;
00179               } else if ( authenticated == 0 ) {
00180                      gss_release_buffer( &minor, &gss_value );
00181                      gss_release_buffer( &minor, &gss_display_value );
00182                      continue;
00183               }
00184 
00185               bv_value.bv_len = gss_value.length;
00186               bv_value.bv_val = (char *)gss_value.value;
00187 
00188               if ( !ber_bvccmp( &gssattr->gssattr_value, '*' ) ) {
00189                      if ( gssattr->gssattr_style != ACL_STYLE_BASE ) {
00190                             amatches.dn_count = nmatch;
00191                             AC_MEMCPY( amatches.dn_data, matches, sizeof( amatches.dn_data ) );
00192                      }
00193 
00194                      switch ( gssattr->gssattr_style ) {
00195                      case ACL_STYLE_REGEX:
00196                             /* XXX assumes value NUL terminated */
00197                             granted = regex_matches( &gssattr->gssattr_value, bv_value.bv_val,
00198                                                    &target->e_nname, val, &amatches );
00199                             break;
00200                      case ACL_STYLE_EXPAND: {
00201                             struct berval bv;
00202                             char buf[ACL_BUF_SIZE];
00203 
00204                             bv.bv_len = sizeof( buf ) - 1;
00205                             bv.bv_val = buf;
00206 
00207                             granted = ( acl_string_expand( &bv, &gssattr->gssattr_value,
00208                                                         &target->e_nname, val,
00209                                                         &amatches ) == 0 ) &&
00210                                      ( ber_bvstrcmp( &bv, &bv_value) == 0 );
00211                             break;
00212                      }
00213                      case ACL_STYLE_BASE:
00214                             granted = ( ber_bvstrcmp( &gssattr->gssattr_value, &bv_value ) == 0 );
00215                             break;
00216                      default:
00217                             assert(0);
00218                             break;
00219                      }
00220               } else {
00221                      granted = 1;
00222               }
00223 
00224               gss_release_buffer( &minor, &gss_value );
00225               gss_release_buffer( &minor, &gss_display_value );
00226 
00227               if ( granted ) {
00228                      break;
00229               }
00230        }
00231 
00232        if ( granted ) {
00233               ACL_LVL_ASSIGN_WRITE( *grant );
00234        }
00235 
00236        return 0;
00237 }
00238 
00239 static int
00240 gssattr_dynacl_destroy(
00241        void          *priv )
00242 {
00243        gssattr_t            *gssattr = (gssattr_t *)priv;
00244 
00245        if ( gssattr != NULL ) {
00246               if ( !BER_BVISNULL( &gssattr->gssattr_name ) ) {
00247                      ber_memfree( gssattr->gssattr_name.bv_val );
00248               }
00249               if ( !BER_BVISNULL( &gssattr->gssattr_value ) ) {
00250                      ber_memfree( gssattr->gssattr_value.bv_val );
00251               }
00252               ch_free( gssattr );
00253        }
00254 
00255        return 0;
00256 }
00257 
00258 static struct slap_dynacl_t gssattr_dynacl = {
00259        "gss",
00260        gssattr_dynacl_parse,
00261        gssattr_dynacl_unparse,
00262        gssattr_dynacl_mask,
00263        gssattr_dynacl_destroy
00264 };
00265 
00266 int
00267 init_module( int argc, char *argv[] )
00268 {
00269        return slap_dynacl_register( &gssattr_dynacl );
00270 }
00271 
00272 
00273 static int
00274 regex_matches(
00275        struct berval *pat,         /* pattern to expand and match against */
00276        char          *str,         /* string to match against pattern */
00277        struct berval *dn_matches,  /* buffer with $N expansion variables from DN */
00278        struct berval *val_matches, /* buffer with $N expansion variables from val */
00279        AclRegexMatches      *matches      /* offsets in buffer for $N expansion variables */
00280 )
00281 {
00282        regex_t re;
00283        char newbuf[ACL_BUF_SIZE];
00284        struct berval bv;
00285        int    rc;
00286 
00287        bv.bv_len = sizeof( newbuf ) - 1;
00288        bv.bv_val = newbuf;
00289 
00290        if (str == NULL) {
00291               str = "";
00292        };
00293 
00294        acl_string_expand( &bv, pat, dn_matches, val_matches, matches );
00295        rc = regcomp( &re, newbuf, REG_EXTENDED|REG_ICASE );
00296        if ( rc ) {
00297               char error[ACL_BUF_SIZE];
00298               regerror( rc, &re, error, sizeof( error ) );
00299 
00300               Debug( LDAP_DEBUG_TRACE,
00301                   "compile( \"%s\", \"%s\") failed %s\n",
00302                      pat->bv_val, str, error );
00303               return( 0 );
00304        }
00305 
00306        rc = regexec( &re, str, 0, NULL, 0 );
00307        regfree( &re );
00308 
00309        Debug( LDAP_DEBUG_TRACE,
00310            "=> regex_matches: string:      %s\n", str, 0, 0 );
00311        Debug( LDAP_DEBUG_TRACE,
00312            "=> regex_matches: rc: %d %s\n",
00313               rc, !rc ? "matches" : "no matches", 0 );
00314        return( !rc );
00315 }
00316