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