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