1/* posixgroup.c */ 2/* $OpenLDAP$ */ 3/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 4 * 5 * Copyright 1998-2011 The OpenLDAP Foundation. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted only as authorized by the OpenLDAP 10 * Public License. 11 * 12 * A copy of this license is available in the file LICENSE in the 13 * top-level directory of the distribution or, alternatively, at 14 * <http://www.OpenLDAP.org/license.html>. 15 */ 16 17#include <portable.h> 18 19#include <ac/string.h> 20#include <slap.h> 21#include <lutil.h> 22 23/* Need dynacl... */ 24 25#ifdef SLAP_DYNACL 26 27typedef struct pg_t { 28 slap_style_t pg_style; 29 struct berval pg_pat; 30} pg_t; 31 32static ObjectClass *pg_posixGroup; 33static AttributeDescription *pg_memberUid; 34static ObjectClass *pg_posixAccount; 35static AttributeDescription *pg_uidNumber; 36 37static int pg_dynacl_destroy( void *priv ); 38 39static int 40pg_dynacl_parse( 41 const char *fname, 42 int lineno, 43 const char *opts, 44 slap_style_t style, 45 const char *pattern, 46 void **privp ) 47{ 48 pg_t *pg; 49 int rc; 50 const char *text = NULL; 51 struct berval pat; 52 53 ber_str2bv( pattern, 0, 0, &pat ); 54 55 pg = ch_calloc( 1, sizeof( pg_t ) ); 56 57 pg->pg_style = style; 58 59 switch ( pg->pg_style ) { 60 case ACL_STYLE_BASE: 61 rc = dnNormalize( 0, NULL, NULL, &pat, &pg->pg_pat, NULL ); 62 if ( rc != LDAP_SUCCESS ) { 63 fprintf( stderr, "%s line %d: posixGroup ACL: " 64 "unable to normalize DN \"%s\".\n", 65 fname, lineno, pattern ); 66 goto cleanup; 67 } 68 break; 69 70 case ACL_STYLE_EXPAND: 71 ber_dupbv( &pg->pg_pat, &pat ); 72 break; 73 74 default: 75 fprintf( stderr, "%s line %d: posixGroup ACL: " 76 "unsupported style \"%s\".\n", 77 fname, lineno, style_strings[ pg->pg_style ] ); 78 goto cleanup; 79 } 80 81 /* TODO: use opts to allow the use of different 82 * group objects and member attributes */ 83 if ( pg_posixGroup == NULL ) { 84 pg_posixGroup = oc_find( "posixGroup" ); 85 if ( pg_posixGroup == NULL ) { 86 fprintf( stderr, "%s line %d: posixGroup ACL: " 87 "unable to lookup \"posixGroup\" " 88 "objectClass.\n", 89 fname, lineno ); 90 goto cleanup; 91 } 92 93 pg_posixAccount = oc_find( "posixAccount" ); 94 if ( pg_posixGroup == NULL ) { 95 fprintf( stderr, "%s line %d: posixGroup ACL: " 96 "unable to lookup \"posixAccount\" " 97 "objectClass.\n", 98 fname, lineno ); 99 goto cleanup; 100 } 101 102 rc = slap_str2ad( "memberUid", &pg_memberUid, &text ); 103 if ( rc != LDAP_SUCCESS ) { 104 fprintf( stderr, "%s line %d: posixGroup ACL: " 105 "unable to lookup \"memberUid\" " 106 "attributeDescription (%d: %s).\n", 107 fname, lineno, rc, text ); 108 goto cleanup; 109 } 110 111 rc = slap_str2ad( "uidNumber", &pg_uidNumber, &text ); 112 if ( rc != LDAP_SUCCESS ) { 113 fprintf( stderr, "%s line %d: posixGroup ACL: " 114 "unable to lookup \"uidNumber\" " 115 "attributeDescription (%d: %s).\n", 116 fname, lineno, rc, text ); 117 goto cleanup; 118 } 119 } 120 121 *privp = (void *)pg; 122 return 0; 123 124cleanup: 125 (void)pg_dynacl_destroy( (void *)pg ); 126 127 return 1; 128} 129 130static int 131pg_dynacl_unparse( 132 void *priv, 133 struct berval *bv ) 134{ 135 pg_t *pg = (pg_t *)priv; 136 char *ptr; 137 138 bv->bv_len = STRLENOF( " dynacl/posixGroup.expand=" ) + pg->pg_pat.bv_len; 139 bv->bv_val = ch_malloc( bv->bv_len + 1 ); 140 141 ptr = lutil_strcopy( bv->bv_val, " dynacl/posixGroup" ); 142 143 switch ( pg->pg_style ) { 144 case ACL_STYLE_BASE: 145 ptr = lutil_strcopy( ptr, ".exact=" ); 146 break; 147 148 case ACL_STYLE_EXPAND: 149 ptr = lutil_strcopy( ptr, ".expand=" ); 150 break; 151 152 default: 153 assert( 0 ); 154 } 155 156 ptr = lutil_strncopy( ptr, pg->pg_pat.bv_val, pg->pg_pat.bv_len ); 157 ptr[ 0 ] = '\0'; 158 159 bv->bv_len = ptr - bv->bv_val; 160 161 return 0; 162} 163 164static int 165pg_dynacl_mask( 166 void *priv, 167 Operation *op, 168 Entry *target, 169 AttributeDescription *desc, 170 struct berval *val, 171 int nmatch, 172 regmatch_t *matches, 173 slap_access_t *grant, 174 slap_access_t *deny ) 175{ 176 pg_t *pg = (pg_t *)priv; 177 Entry *group = NULL, 178 *user = NULL; 179 int rc; 180 Backend *be = op->o_bd, 181 *group_be = NULL, 182 *user_be = NULL; 183 struct berval group_ndn; 184 185 ACL_INVALIDATE( *deny ); 186 187 /* get user */ 188 if ( target && dn_match( &target->e_nname, &op->o_ndn ) ) { 189 user = target; 190 rc = LDAP_SUCCESS; 191 192 } else { 193 user_be = op->o_bd = select_backend( &op->o_ndn, 0 ); 194 if ( op->o_bd == NULL ) { 195 op->o_bd = be; 196 return 0; 197 } 198 rc = be_entry_get_rw( op, &op->o_ndn, pg_posixAccount, pg_uidNumber, 0, &user ); 199 } 200 201 if ( rc != LDAP_SUCCESS || user == NULL ) { 202 op->o_bd = be; 203 return 0; 204 } 205 206 /* get target */ 207 if ( pg->pg_style == ACL_STYLE_EXPAND ) { 208 char buf[ 1024 ]; 209 struct berval bv; 210 AclRegexMatches amatches = { 0 }; 211 212 amatches.dn_count = nmatch; 213 AC_MEMCPY( amatches.dn_data, matches, sizeof( amatches.dn_data ) ); 214 215 bv.bv_len = sizeof( buf ) - 1; 216 bv.bv_val = buf; 217 218 if ( acl_string_expand( &bv, &pg->pg_pat, 219 &target->e_nname, 220 NULL, &amatches ) ) 221 { 222 goto cleanup; 223 } 224 225 if ( dnNormalize( 0, NULL, NULL, &bv, &group_ndn, 226 op->o_tmpmemctx ) != LDAP_SUCCESS ) 227 { 228 /* did not expand to a valid dn */ 229 goto cleanup; 230 } 231 232 } else { 233 group_ndn = pg->pg_pat; 234 } 235 236 if ( target && dn_match( &target->e_nname, &group_ndn ) ) { 237 group = target; 238 rc = LDAP_SUCCESS; 239 240 } else { 241 group_be = op->o_bd = select_backend( &group_ndn, 0 ); 242 if ( op->o_bd == NULL ) { 243 goto cleanup; 244 } 245 rc = be_entry_get_rw( op, &group_ndn, pg_posixGroup, pg_memberUid, 0, &group ); 246 } 247 248 if ( group_ndn.bv_val != pg->pg_pat.bv_val ) { 249 op->o_tmpfree( group_ndn.bv_val, op->o_tmpmemctx ); 250 } 251 252 if ( rc == LDAP_SUCCESS && group != NULL ) { 253 Attribute *a_uid, 254 *a_member; 255 256 a_uid = attr_find( user->e_attrs, pg_uidNumber ); 257 if ( !a_uid || !BER_BVISNULL( &a_uid->a_nvals[ 1 ] ) ) { 258 rc = LDAP_NO_SUCH_ATTRIBUTE; 259 260 } else { 261 a_member = attr_find( group->e_attrs, pg_memberUid ); 262 if ( !a_member ) { 263 rc = LDAP_NO_SUCH_ATTRIBUTE; 264 265 } else { 266 rc = value_find_ex( pg_memberUid, 267 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | 268 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, 269 a_member->a_nvals, &a_uid->a_nvals[ 0 ], 270 op->o_tmpmemctx ); 271 } 272 } 273 274 } else { 275 rc = LDAP_NO_SUCH_OBJECT; 276 } 277 278 279 if ( rc == LDAP_SUCCESS ) { 280 ACL_LVL_ASSIGN_WRITE( *grant ); 281 } 282 283cleanup:; 284 if ( group != NULL && group != target ) { 285 op->o_bd = group_be; 286 be_entry_release_r( op, group ); 287 op->o_bd = be; 288 } 289 290 if ( user != NULL && user != target ) { 291 op->o_bd = user_be; 292 be_entry_release_r( op, user ); 293 op->o_bd = be; 294 } 295 296 return 0; 297} 298 299static int 300pg_dynacl_destroy( 301 void *priv ) 302{ 303 pg_t *pg = (pg_t *)priv; 304 305 if ( pg != NULL ) { 306 if ( !BER_BVISNULL( &pg->pg_pat ) ) { 307 ber_memfree( pg->pg_pat.bv_val ); 308 } 309 ch_free( pg ); 310 } 311 312 return 0; 313} 314 315static struct slap_dynacl_t pg_dynacl = { 316 "posixGroup", 317 pg_dynacl_parse, 318 pg_dynacl_unparse, 319 pg_dynacl_mask, 320 pg_dynacl_destroy 321}; 322 323int 324init_module( int argc, char *argv[] ) 325{ 326 return slap_dynacl_register( &pg_dynacl ); 327} 328 329#endif /* SLAP_DYNACL */ 330