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