]> git.sur5r.net Git - openldap/blob - contrib/slapd-modules/acl/posixgroup.c
Happy New Year!
[openldap] / contrib / slapd-modules / acl / posixgroup.c
1 /* posixgroup.c */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 1998-2017 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in the file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16
17 #include <portable.h>
18
19 #include <ac/string.h>
20 #include <slap.h>
21 #include <lutil.h>
22
23 /* Need dynacl... */
24
25 #ifdef SLAP_DYNACL
26
27 typedef struct pg_t {
28         slap_style_t            pg_style;
29         struct berval           pg_pat;
30 } pg_t;
31
32 static ObjectClass              *pg_posixGroup;
33 static AttributeDescription     *pg_memberUid;
34 static ObjectClass              *pg_posixAccount;
35 static AttributeDescription     *pg_uidNumber;
36
37 static int pg_dynacl_destroy( void *priv );
38
39 static int
40 pg_dynacl_parse(
41         const char      *fname,
42         int             lineno,
43         const char      *opts,
44         slap_style_t    style,
45         const char      *pattern,
46         void            **privp )
47 {
48         pg_t            *pg;
49         int             rc;
50         const char      *text = NULL;
51         struct berval   pat;
52
53         ber_str2bv( pattern, 0, 0, &pat );
54
55         pg = ch_calloc( 1, sizeof( pg_t ) );
56
57         pg->pg_style = style;
58
59         switch ( pg->pg_style ) {
60         case ACL_STYLE_BASE:
61                 rc = dnNormalize( 0, NULL, NULL, &pat, &pg->pg_pat, NULL );
62                 if ( rc != LDAP_SUCCESS ) {
63                         fprintf( stderr, "%s line %d: posixGroup ACL: "
64                                 "unable to normalize DN \"%s\".\n",
65                                 fname, lineno, pattern );
66                         goto cleanup;
67                 }
68                 break;
69
70         case ACL_STYLE_EXPAND:
71                 ber_dupbv( &pg->pg_pat, &pat );
72                 break;
73
74         default:
75                 fprintf( stderr, "%s line %d: posixGroup ACL: "
76                         "unsupported style \"%s\".\n",
77                         fname, lineno, style_strings[ pg->pg_style ] );
78                 goto cleanup;
79         }
80
81         /* TODO: use opts to allow the use of different
82          * group objects and member attributes */
83         if ( pg_posixGroup == NULL ) {
84                 pg_posixGroup = oc_find( "posixGroup" );
85                 if ( pg_posixGroup == NULL ) {
86                         fprintf( stderr, "%s line %d: posixGroup ACL: "
87                                 "unable to lookup \"posixGroup\" "
88                                 "objectClass.\n",
89                                 fname, lineno );
90                         goto cleanup;
91                 }
92
93                 pg_posixAccount = oc_find( "posixAccount" );
94                 if ( pg_posixGroup == NULL ) {
95                         fprintf( stderr, "%s line %d: posixGroup ACL: "
96                                 "unable to lookup \"posixAccount\" "
97                                 "objectClass.\n",
98                                 fname, lineno );
99                         goto cleanup;
100                 }
101
102                 rc = slap_str2ad( "memberUid", &pg_memberUid, &text );
103                 if ( rc != LDAP_SUCCESS ) {
104                         fprintf( stderr, "%s line %d: posixGroup ACL: "
105                                 "unable to lookup \"memberUid\" "
106                                 "attributeDescription (%d: %s).\n",
107                                 fname, lineno, rc, text );
108                         goto cleanup;
109                 }
110
111                 rc = slap_str2ad( "uidNumber", &pg_uidNumber, &text );
112                 if ( rc != LDAP_SUCCESS ) {
113                         fprintf( stderr, "%s line %d: posixGroup ACL: "
114                                 "unable to lookup \"uidNumber\" "
115                                 "attributeDescription (%d: %s).\n",
116                                 fname, lineno, rc, text );
117                         goto cleanup;
118                 }
119         }
120
121         *privp = (void *)pg;
122         return 0;
123
124 cleanup:
125         (void)pg_dynacl_destroy( (void *)pg );
126
127         return 1;
128 }
129
130 static int
131 pg_dynacl_unparse(
132         void            *priv,
133         struct berval   *bv )
134 {
135         pg_t            *pg = (pg_t *)priv;
136         char            *ptr;
137
138         bv->bv_len = STRLENOF( " dynacl/posixGroup.expand=" ) + pg->pg_pat.bv_len;
139         bv->bv_val = ch_malloc( bv->bv_len + 1 );
140
141         ptr = lutil_strcopy( bv->bv_val, " dynacl/posixGroup" );
142
143         switch ( pg->pg_style ) {
144         case ACL_STYLE_BASE:
145                 ptr = lutil_strcopy( ptr, ".exact=" );
146                 break;
147
148         case ACL_STYLE_EXPAND:
149                 ptr = lutil_strcopy( ptr, ".expand=" );
150                 break;
151
152         default:
153                 assert( 0 );
154         }
155
156         ptr = lutil_strncopy( ptr, pg->pg_pat.bv_val, pg->pg_pat.bv_len );
157         ptr[ 0 ] = '\0';
158
159         bv->bv_len = ptr - bv->bv_val;
160
161         return 0;
162 }
163
164 static int
165 pg_dynacl_mask(
166         void                    *priv,
167         Operation               *op,
168         Entry                   *target,
169         AttributeDescription    *desc,
170         struct berval           *val,
171         int                     nmatch,
172         regmatch_t              *matches,
173         slap_access_t           *grant,
174         slap_access_t           *deny )
175 {
176         pg_t            *pg = (pg_t *)priv;
177         Entry           *group = NULL,
178                         *user = NULL;
179         int             rc;
180         Backend         *be = op->o_bd,
181                         *group_be = NULL,
182                         *user_be = NULL;
183         struct berval   group_ndn;
184
185         ACL_INVALIDATE( *deny );
186
187         /* get user */
188         if ( target && dn_match( &target->e_nname, &op->o_ndn ) ) {
189                 user = target;
190                 rc = LDAP_SUCCESS;
191
192         } else {
193                 user_be = op->o_bd = select_backend( &op->o_ndn, 0 );
194                 if ( op->o_bd == NULL ) {
195                         op->o_bd = be;
196                         return 0;
197                 }
198                 rc = be_entry_get_rw( op, &op->o_ndn, pg_posixAccount, pg_uidNumber, 0, &user );
199         }
200
201         if ( rc != LDAP_SUCCESS || user == NULL ) {
202                 op->o_bd = be;
203                 return 0;
204         }
205
206         /* get target */
207         if ( pg->pg_style == ACL_STYLE_EXPAND ) {
208                 char            buf[ 1024 ];
209                 struct berval   bv;
210                 AclRegexMatches amatches = { 0 };
211
212                 amatches.dn_count = nmatch;
213                 AC_MEMCPY( amatches.dn_data, matches, sizeof( amatches.dn_data ) );
214
215                 bv.bv_len = sizeof( buf ) - 1;
216                 bv.bv_val = buf;
217
218                 if ( acl_string_expand( &bv, &pg->pg_pat,
219                                 &target->e_nname,
220                                 NULL, &amatches ) )
221                 {
222                         goto cleanup;
223                 }
224
225                 if ( dnNormalize( 0, NULL, NULL, &bv, &group_ndn,
226                                 op->o_tmpmemctx ) != LDAP_SUCCESS )
227                 {
228                         /* did not expand to a valid dn */
229                         goto cleanup;
230                 }
231                 
232         } else {
233                 group_ndn = pg->pg_pat;
234         }
235
236         if ( target && dn_match( &target->e_nname, &group_ndn ) ) {
237                 group = target;
238                 rc = LDAP_SUCCESS;
239
240         } else {
241                 group_be = op->o_bd = select_backend( &group_ndn, 0 );
242                 if ( op->o_bd == NULL ) {
243                         goto cleanup;
244                 }
245                 rc = be_entry_get_rw( op, &group_ndn, pg_posixGroup, pg_memberUid, 0, &group );
246         }
247
248         if ( group_ndn.bv_val != pg->pg_pat.bv_val ) {
249                 op->o_tmpfree( group_ndn.bv_val, op->o_tmpmemctx );
250         }
251
252         if ( rc == LDAP_SUCCESS && group != NULL ) {
253                 Attribute       *a_uid,
254                                 *a_member;
255
256                 a_uid = attr_find( user->e_attrs, pg_uidNumber );
257                 if ( !a_uid || !BER_BVISNULL( &a_uid->a_nvals[ 1 ] ) ) {
258                         rc = LDAP_NO_SUCH_ATTRIBUTE;
259
260                 } else {
261                         a_member = attr_find( group->e_attrs, pg_memberUid );
262                         if ( !a_member ) {
263                                 rc = LDAP_NO_SUCH_ATTRIBUTE;
264
265                         } else {
266                                 rc = value_find_ex( pg_memberUid,
267                                         SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
268                                         SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
269                                         a_member->a_nvals, &a_uid->a_nvals[ 0 ],
270                                         op->o_tmpmemctx );
271                         }
272                 }
273
274         } else {
275                 rc = LDAP_NO_SUCH_OBJECT;
276         }
277
278
279         if ( rc == LDAP_SUCCESS ) {
280                 ACL_LVL_ASSIGN_WRITE( *grant );
281         }
282
283 cleanup:;
284         if ( group != NULL && group != target ) {
285                 op->o_bd = group_be;
286                 be_entry_release_r( op, group );
287                 op->o_bd = be;
288         }
289
290         if ( user != NULL && user != target ) {
291                 op->o_bd = user_be;
292                 be_entry_release_r( op, user );
293                 op->o_bd = be;
294         }
295
296         return 0;
297 }
298
299 static int
300 pg_dynacl_destroy(
301         void            *priv )
302 {
303         pg_t            *pg = (pg_t *)priv;
304
305         if ( pg != NULL ) {
306                 if ( !BER_BVISNULL( &pg->pg_pat ) ) {
307                         ber_memfree( pg->pg_pat.bv_val );
308                 }
309                 ch_free( pg );
310         }
311
312         return 0;
313 }
314
315 static struct slap_dynacl_t pg_dynacl = {
316         "posixGroup",
317         pg_dynacl_parse,
318         pg_dynacl_unparse,
319         pg_dynacl_mask,
320         pg_dynacl_destroy
321 };
322
323 int
324 init_module( int argc, char *argv[] )
325 {
326         return slap_dynacl_register( &pg_dynacl );
327 }
328
329 #endif /* SLAP_DYNACL */