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