xref: /netbsd-src/external/bsd/openldap/dist/contrib/slapd-modules/acl/posixgroup.c (revision 500db002748d9818288e46e10f026a2b09548086)
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