1 /* $NetBSD: posixgroup.c,v 1.1.1.3 2010/12/12 15:18:53 adam Exp $ */ 2 3 /* posixgroup.c */ 4 /* OpenLDAP: pkg/ldap/contrib/slapd-modules/acl/posixgroup.c,v 1.3.2.7 2010/04/13 20:22:25 kurt Exp */ 5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 1998-2010 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 struct slap_op *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, 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 213 bv.bv_len = sizeof( buf ) - 1; 214 bv.bv_val = buf; 215 216 if ( acl_string_expand( &bv, &pg->pg_pat, 217 target->e_nname.bv_val, 218 nmatch, matches ) ) 219 { 220 goto cleanup; 221 } 222 223 if ( dnNormalize( 0, NULL, NULL, &bv, &group_ndn, 224 op->o_tmpmemctx ) != LDAP_SUCCESS ) 225 { 226 /* did not expand to a valid dn */ 227 goto cleanup; 228 } 229 230 } else { 231 group_ndn = pg->pg_pat; 232 } 233 234 if ( target && dn_match( &target->e_nname, &group_ndn ) ) { 235 group = target; 236 rc = LDAP_SUCCESS; 237 238 } else { 239 group_be = op->o_bd = select_backend( &group_ndn, 0, 0 ); 240 if ( op->o_bd == NULL ) { 241 goto cleanup; 242 } 243 rc = be_entry_get_rw( op, &group_ndn, pg_posixGroup, pg_memberUid, 0, &group ); 244 } 245 246 if ( group_ndn.bv_val != pg->pg_pat.bv_val ) { 247 op->o_tmpfree( group_ndn.bv_val, op->o_tmpmemctx ); 248 } 249 250 if ( rc == LDAP_SUCCESS && group != NULL ) { 251 Attribute *a_uid, 252 *a_member; 253 254 a_uid = attr_find( user->e_attrs, pg_uidNumber ); 255 if ( !a_uid || !BER_BVISNULL( &a_uid->a_nvals[ 1 ] ) ) { 256 rc = LDAP_NO_SUCH_ATTRIBUTE; 257 258 } else { 259 a_member = attr_find( group->e_attrs, pg_memberUid ); 260 if ( !a_member ) { 261 rc = LDAP_NO_SUCH_ATTRIBUTE; 262 263 } else { 264 rc = value_find_ex( pg_memberUid, 265 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | 266 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, 267 a_member->a_nvals, &a_uid->a_nvals[ 0 ], 268 op->o_tmpmemctx ); 269 } 270 } 271 272 } else { 273 rc = LDAP_NO_SUCH_OBJECT; 274 } 275 276 277 if ( rc == LDAP_SUCCESS ) { 278 ACL_LVL_ASSIGN_WRITE( *grant ); 279 } 280 281 cleanup:; 282 if ( group != NULL && group != target ) { 283 op->o_bd = group_be; 284 be_entry_release_r( op, group ); 285 op->o_bd = be; 286 } 287 288 if ( user != NULL && user != target ) { 289 op->o_bd = user_be; 290 be_entry_release_r( op, user ); 291 op->o_bd = be; 292 } 293 294 return 0; 295 } 296 297 static int 298 pg_dynacl_destroy( 299 void *priv ) 300 { 301 pg_t *pg = (pg_t *)priv; 302 303 if ( pg != NULL ) { 304 if ( !BER_BVISNULL( &pg->pg_pat ) ) { 305 ber_memfree( pg->pg_pat.bv_val ); 306 } 307 ch_free( pg ); 308 } 309 310 return 0; 311 } 312 313 static struct slap_dynacl_t pg_dynacl = { 314 "posixGroup", 315 pg_dynacl_parse, 316 pg_dynacl_unparse, 317 pg_dynacl_mask, 318 pg_dynacl_destroy 319 }; 320 321 int 322 init_module( int argc, char *argv[] ) 323 { 324 return slap_dynacl_register( &pg_dynacl ); 325 } 326 327 #endif /* SLAP_DYNACL */ 328