mirror of
https://git.openldap.org/openldap/openldap.git
synced 2025-12-27 18:19:52 -05:00
Add GSS naming extensions ACL plugin
This commit is contained in:
parent
45dfacd9d5
commit
93c54fd158
2 changed files with 349 additions and 0 deletions
33
contrib/slapd-modules/acl/README.gssacl
Normal file
33
contrib/slapd-modules/acl/README.gssacl
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
This directory contains native slapd plugins that implement access rules.
|
||||
|
||||
gssacl.c contains a simple example that implements access control
|
||||
based on GSS naming extensions attributes.
|
||||
|
||||
To use the acl-gssacl plugin, add:
|
||||
|
||||
moduleload acl-gssacl.so
|
||||
|
||||
to your slapd configuration file.
|
||||
It is configured using
|
||||
|
||||
access to <what>
|
||||
by dynacl/gss/<attribute>.[.{base,regex,expand}]=<valpat> {<level>|<priv(s)>}
|
||||
|
||||
The default is "exact"; in case of "expand", "<valpat>" results from
|
||||
the expansion of submatches in the "<what>" portion. "<level>|<priv(s)>"
|
||||
describe the level of privilege this rule can assume.
|
||||
|
||||
No Makefile is provided. Use a command line similar to:
|
||||
|
||||
gcc -shared -I../../../include -I../../../servers/slapd -Wall -g \
|
||||
-o acl-gssacl.so gssacl.c
|
||||
|
||||
to compile the gssacl ACL plugin.
|
||||
|
||||
---
|
||||
Copyright 2011 PADL Software Pty Ltd. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted only as authorized by the OpenLDAP
|
||||
Public License.
|
||||
|
||||
316
contrib/slapd-modules/acl/gssacl.c
Normal file
316
contrib/slapd-modules/acl/gssacl.c
Normal file
|
|
@ -0,0 +1,316 @@
|
|||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 2011 PADL Software Pty Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted only as authorized by the OpenLDAP
|
||||
* Public License.
|
||||
*
|
||||
* A copy of this license is available in the file LICENSE in the
|
||||
* top-level directory of the distribution or, alternatively, at
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
|
||||
#include <portable.h>
|
||||
|
||||
#include <ac/string.h>
|
||||
#include <slap.h>
|
||||
#include <lutil.h>
|
||||
|
||||
#include <sasl/sasl.h>
|
||||
#include <gssapi/gssapi.h>
|
||||
#include <gssapi/gssapi_ext.h>
|
||||
|
||||
#define ACL_BUF_SIZE 1024
|
||||
|
||||
typedef struct gssattr_t {
|
||||
slap_style_t gssattr_style;
|
||||
struct berval gssattr_name; /* asserted name */
|
||||
struct berval gssattr_value; /* asserted value */
|
||||
} gssattr_t;
|
||||
|
||||
static int gssattr_dynacl_destroy( void *priv );
|
||||
|
||||
static int
|
||||
regex_matches(
|
||||
struct berval *pat, /* pattern to expand and match against */
|
||||
char *str, /* string to match against pattern */
|
||||
struct berval *dn_matches, /* buffer with $N expansion variables from DN */
|
||||
struct berval *val_matches, /* buffer with $N expansion variables from val */
|
||||
AclRegexMatches *matches /* offsets in buffer for $N expansion variables */
|
||||
);
|
||||
|
||||
static int
|
||||
gssattr_dynacl_parse(
|
||||
const char *fname,
|
||||
int lineno,
|
||||
const char *opts,
|
||||
slap_style_t style,
|
||||
const char *pattern,
|
||||
void **privp )
|
||||
{
|
||||
gssattr_t *gssattr;
|
||||
|
||||
gssattr = (gssattr_t *)ch_calloc( 1, sizeof( gssattr_t ) );
|
||||
|
||||
if ( opts == NULL || opts[0] == '\0' ) {
|
||||
fprintf( stderr, "%s line %d: GSS ACL: no attribute specified.\n",
|
||||
fname, lineno );
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if ( pattern == NULL || pattern[0] == '\0' ) {
|
||||
fprintf( stderr, "%s line %d: GSS ACL: no attribute value specified.\n",
|
||||
fname, lineno );
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
gssattr->gssattr_style = style;
|
||||
|
||||
switch ( gssattr->gssattr_style ) {
|
||||
case ACL_STYLE_BASE:
|
||||
case ACL_STYLE_REGEX:
|
||||
case ACL_STYLE_EXPAND:
|
||||
break;
|
||||
default:
|
||||
fprintf( stderr, "%s line %d: GSS ACL: unsupported style \"%s\".\n",
|
||||
fname, lineno, style_strings[style] );
|
||||
goto cleanup;
|
||||
break;
|
||||
}
|
||||
|
||||
ber_str2bv( opts, 0, 1, &gssattr->gssattr_name );
|
||||
ber_str2bv( pattern, 0, 1, &gssattr->gssattr_value );
|
||||
|
||||
*privp = (void *)gssattr;
|
||||
return 0;
|
||||
|
||||
cleanup:
|
||||
(void)gssattr_dynacl_destroy( (void *)gssattr );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
gssattr_dynacl_unparse(
|
||||
void *priv,
|
||||
struct berval *bv )
|
||||
{
|
||||
gssattr_t *gssattr = (gssattr_t *)priv;
|
||||
char *ptr;
|
||||
|
||||
bv->bv_len = STRLENOF( " dynacl/gss/.expand=" ) +
|
||||
gssattr->gssattr_name.bv_len +
|
||||
gssattr->gssattr_value.bv_len;
|
||||
bv->bv_val = ch_malloc( bv->bv_len + 1 );
|
||||
|
||||
ptr = lutil_strcopy( bv->bv_val, " dynacl/gss/" );
|
||||
ptr = lutil_strncopy( ptr, gssattr->gssattr_name.bv_val,
|
||||
gssattr->gssattr_name.bv_len );
|
||||
switch ( gssattr->gssattr_style ) {
|
||||
case ACL_STYLE_BASE:
|
||||
ptr = lutil_strcopy( ptr, ".exact=" );
|
||||
break;
|
||||
case ACL_STYLE_REGEX:
|
||||
ptr = lutil_strcopy( ptr, ".regex=" );
|
||||
break;
|
||||
case ACL_STYLE_EXPAND:
|
||||
ptr = lutil_strcopy( ptr, ".expand=" );
|
||||
break;
|
||||
default:
|
||||
assert( 0 );
|
||||
break;
|
||||
}
|
||||
|
||||
ptr = lutil_strncopy( ptr, gssattr->gssattr_value.bv_val,
|
||||
gssattr->gssattr_value.bv_len );
|
||||
|
||||
ptr[ 0 ] = '\0';
|
||||
|
||||
bv->bv_len = ptr - bv->bv_val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
gssattr_dynacl_mask(
|
||||
void *priv,
|
||||
Operation *op,
|
||||
Entry *target,
|
||||
AttributeDescription *desc,
|
||||
struct berval *val,
|
||||
int nmatch,
|
||||
regmatch_t *matches,
|
||||
slap_access_t *grant,
|
||||
slap_access_t *deny )
|
||||
{
|
||||
gssattr_t *gssattr = (gssattr_t *)priv;
|
||||
sasl_conn_t *sasl_ctx = op->o_conn->c_sasl_authctx;
|
||||
gss_name_t gss_name = GSS_C_NO_NAME;
|
||||
OM_uint32 major, minor;
|
||||
int more = -1;
|
||||
int authenticated, complete;
|
||||
gss_buffer_desc attr = GSS_C_EMPTY_BUFFER;
|
||||
int granted = 0;
|
||||
|
||||
ACL_INVALIDATE( *deny );
|
||||
|
||||
if ( sasl_ctx == NULL ||
|
||||
sasl_getprop( sasl_ctx, SASL_GSS_PEER_NAME, (const void **)&gss_name) != 0 ||
|
||||
gss_name == GSS_C_NO_NAME ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
attr.length = gssattr->gssattr_name.bv_len;
|
||||
attr.value = gssattr->gssattr_name.bv_val;
|
||||
|
||||
while ( more != 0 ) {
|
||||
AclRegexMatches amatches = { 0 };
|
||||
gss_buffer_desc gss_value = GSS_C_EMPTY_BUFFER;
|
||||
gss_buffer_desc gss_display_value = GSS_C_EMPTY_BUFFER;
|
||||
struct berval bv_value;
|
||||
|
||||
major = gss_get_name_attribute( &minor, gss_name, &attr,
|
||||
&authenticated, &complete,
|
||||
&gss_value, &gss_display_value, &more );
|
||||
if ( GSS_ERROR( major ) ) {
|
||||
break;
|
||||
} else if ( authenticated == 0 ) {
|
||||
gss_release_buffer( &minor, &gss_value );
|
||||
gss_release_buffer( &minor, &gss_display_value );
|
||||
continue;
|
||||
}
|
||||
|
||||
bv_value.bv_len = gss_value.length;
|
||||
bv_value.bv_val = (char *)gss_value.value;
|
||||
|
||||
if ( !ber_bvccmp( &gssattr->gssattr_value, '*' ) ) {
|
||||
if ( gssattr->gssattr_style != ACL_STYLE_BASE ) {
|
||||
amatches.dn_count = nmatch;
|
||||
AC_MEMCPY( amatches.dn_data, matches, sizeof( amatches.dn_data ) );
|
||||
}
|
||||
|
||||
switch ( gssattr->gssattr_style ) {
|
||||
case ACL_STYLE_REGEX:
|
||||
/* XXX assumes value NUL terminated */
|
||||
granted = regex_matches( &gssattr->gssattr_value, bv_value.bv_val,
|
||||
&target->e_nname, val, &amatches );
|
||||
break;
|
||||
case ACL_STYLE_EXPAND: {
|
||||
struct berval bv;
|
||||
char buf[ACL_BUF_SIZE];
|
||||
|
||||
bv.bv_len = sizeof( buf ) - 1;
|
||||
bv.bv_val = buf;
|
||||
|
||||
granted = ( acl_string_expand( &bv, &gssattr->gssattr_value,
|
||||
&target->e_nname, val,
|
||||
&amatches ) == 0 ) &&
|
||||
( ber_bvstrcmp( &bv, &bv_value) == 0 );
|
||||
break;
|
||||
}
|
||||
case ACL_STYLE_BASE:
|
||||
granted = ( ber_bvstrcmp( &gssattr->gssattr_value, &bv_value ) == 0 );
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
granted = 1;
|
||||
}
|
||||
|
||||
gss_release_buffer( &minor, &gss_value );
|
||||
gss_release_buffer( &minor, &gss_display_value );
|
||||
|
||||
if ( granted ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( granted ) {
|
||||
ACL_LVL_ASSIGN_WRITE( *grant );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
gssattr_dynacl_destroy(
|
||||
void *priv )
|
||||
{
|
||||
gssattr_t *gssattr = (gssattr_t *)priv;
|
||||
|
||||
if ( gssattr != NULL ) {
|
||||
if ( !BER_BVISNULL( &gssattr->gssattr_name ) ) {
|
||||
ber_memfree( gssattr->gssattr_name.bv_val );
|
||||
}
|
||||
if ( !BER_BVISNULL( &gssattr->gssattr_value ) ) {
|
||||
ber_memfree( gssattr->gssattr_value.bv_val );
|
||||
}
|
||||
ch_free( gssattr );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct slap_dynacl_t gssattr_dynacl = {
|
||||
"gss",
|
||||
gssattr_dynacl_parse,
|
||||
gssattr_dynacl_unparse,
|
||||
gssattr_dynacl_mask,
|
||||
gssattr_dynacl_destroy
|
||||
};
|
||||
|
||||
int
|
||||
init_module( int argc, char *argv[] )
|
||||
{
|
||||
return slap_dynacl_register( &gssattr_dynacl );
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
regex_matches(
|
||||
struct berval *pat, /* pattern to expand and match against */
|
||||
char *str, /* string to match against pattern */
|
||||
struct berval *dn_matches, /* buffer with $N expansion variables from DN */
|
||||
struct berval *val_matches, /* buffer with $N expansion variables from val */
|
||||
AclRegexMatches *matches /* offsets in buffer for $N expansion variables */
|
||||
)
|
||||
{
|
||||
regex_t re;
|
||||
char newbuf[ACL_BUF_SIZE];
|
||||
struct berval bv;
|
||||
int rc;
|
||||
|
||||
bv.bv_len = sizeof( newbuf ) - 1;
|
||||
bv.bv_val = newbuf;
|
||||
|
||||
if (str == NULL) {
|
||||
str = "";
|
||||
};
|
||||
|
||||
acl_string_expand( &bv, pat, dn_matches, val_matches, matches );
|
||||
rc = regcomp( &re, newbuf, REG_EXTENDED|REG_ICASE );
|
||||
if ( rc ) {
|
||||
char error[ACL_BUF_SIZE];
|
||||
regerror( rc, &re, error, sizeof( error ) );
|
||||
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
"compile( \"%s\", \"%s\") failed %s\n",
|
||||
pat->bv_val, str, error );
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
rc = regexec( &re, str, 0, NULL, 0 );
|
||||
regfree( &re );
|
||||
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
"=> regex_matches: string: %s\n", str, 0, 0 );
|
||||
Debug( LDAP_DEBUG_TRACE,
|
||||
"=> regex_matches: rc: %d %s\n",
|
||||
rc, !rc ? "matches" : "no matches", 0 );
|
||||
return( !rc );
|
||||
}
|
||||
|
||||
Loading…
Reference in a new issue