xref: /netbsd-src/external/bsd/openldap/dist/contrib/slapd-modules/acl/posixgroup.c (revision 549b59ed3ccf0d36d3097190a0db27b770f3a839)
1 /*	$NetBSD: posixgroup.c,v 1.3 2021/08/14 16:14:50 christos Exp $	*/
2 
3 /* posixgroup.c */
4 /* $OpenLDAP$ */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6  *
7  * Copyright 1998-2021 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
pg_dynacl_parse(const char * fname,int lineno,const char * opts,slap_style_t style,const char * pattern,void ** privp)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
pg_dynacl_unparse(void * priv,struct berval * bv)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
pg_dynacl_mask(void * priv,Operation * op,Entry * target,AttributeDescription * desc,struct berval * val,int nmatch,regmatch_t * matches,slap_access_t * grant,slap_access_t * deny)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
pg_dynacl_destroy(void * priv)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
init_module(int argc,char * argv[])326 init_module( int argc, char *argv[] )
327 {
328 	return slap_dynacl_register( &pg_dynacl );
329 }
330 
331 #endif /* SLAP_DYNACL */
332