]> git.sur5r.net Git - openldap/blob - contrib/slapd-modules/authzid/authzid.c
also works for multi-stage binds (ITS#6771; needs ITS#6773 patch)
[openldap] / contrib / slapd-modules / authzid / authzid.c
1 /* vc.c - LDAP Verify Credentials extop (no spec yet) */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2010 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 /* ACKNOWLEDGEMENTS:
17  * This work was initially developed by Pierangelo Masarati for inclusion
18  * in OpenLDAP Software.
19  */
20
21 /*
22  * RFC 3829 Authzid
23  */
24
25 #include "portable.h"
26
27 #include "slap.h"
28 #include "lutil.h"
29 #include "ac/string.h"
30
31 typedef struct ConnExtraAuthzID {
32         ConnExtra ce;
33         char authzid_flag;
34 } ConnExtraAuthzID;
35
36 static int authzid_cid;
37 static slap_overinst authzid;
38
39 static ConnExtraAuthzID *
40 authzid_extra_find( Connection *c )
41 {
42         ConnExtra *cex;
43
44         LDAP_SLIST_FOREACH( cex, &c->c_extra, ce_next ) {
45                 if ( cex->ce_key == (void *)&authzid_cid )
46                         break;
47         }
48
49         return (ConnExtraAuthzID *)cex;
50 }
51
52 static ConnExtraAuthzID *
53 authzid_extra_insert( Connection *c )
54 {
55         ConnExtraAuthzID *cex;
56
57         cex = SLAP_CALLOC( 1, sizeof( ConnExtraAuthzID ) );
58         cex->ce.ce_key = (void *)&authzid_cid;
59
60         LDAP_SLIST_INSERT_HEAD( &c->c_extra, &cex->ce, ce_next );
61
62         return cex;
63 }
64
65 static int
66 authzid_extra_remove( Connection *c )
67 {
68         ConnExtra *cex;
69         int found = 0;
70
71         cex = (ConnExtra *)authzid_extra_find( c );
72         if ( cex ) {
73                 found = 1;
74                 LDAP_SLIST_REMOVE( &c->c_extra, cex, ConnExtra, ce_next );
75                 SLAP_FREE( cex );
76         }
77
78         return found;
79 }
80
81 static int
82 authzid_response(
83         Operation *op,
84         SlapReply *rs )
85 {
86         ConnExtraAuthzID *cex;
87         LDAPControl **ctrls;
88         struct berval edn = BER_BVNULL;
89         ber_len_t len = 0;
90         int n = 0;
91
92         assert( rs->sr_tag = LDAP_RES_BIND );
93
94         cex = authzid_extra_find( op->o_conn );
95         if ( rs->sr_err == LDAP_SASL_BIND_IN_PROGRESS ) {
96                 if ( !cex ) {
97                         cex = authzid_extra_insert( op->o_conn );
98                         cex->authzid_flag = op->o_ctrlflag[ authzid_cid ];
99                 }
100
101                 return SLAP_CB_CONTINUE;
102
103         }
104
105         if ( cex ) {
106                 authzid_extra_remove( op->o_conn );
107         }
108
109         if ( rs->sr_err != LDAP_SUCCESS ) {
110                 return SLAP_CB_CONTINUE;
111         }
112
113         if ( !BER_BVISEMPTY( &op->orb_edn ) ) {
114                 edn = op->orb_edn;
115         } else if ( !BER_BVISEMPTY( &op->o_conn->c_dn ) ) {
116                 edn = op->o_conn->c_dn;
117         }
118
119         if ( !BER_BVISEMPTY( &edn ) ) {
120                 len = STRLENOF("dn:") + edn.bv_len;
121         }
122
123         /* save original controls in sc_private;
124          * will be restored by sc_cleanup
125          */
126         if ( rs->sr_ctrls != NULL ) {
127                 op->o_callback->sc_private = rs->sr_ctrls;
128                 for ( ; rs->sr_ctrls[n] != NULL; n++ )
129                         ;
130         }
131
132         ctrls = op->o_tmpalloc( sizeof( LDAPControl * )*( n + 2 ), op->o_tmpmemctx );
133         n = 0;
134         if ( rs->sr_ctrls ) {
135                 for ( ; rs->sr_ctrls[n] != NULL; n++ ) {
136                         ctrls[n] = rs->sr_ctrls[n];
137                 }
138         }
139
140         /* anonymous: "", otherwise "dn:<dn>" */
141         ctrls[n] = op->o_tmpalloc( sizeof( LDAPControl ) + len + 1, op->o_tmpmemctx );
142         ctrls[n]->ldctl_oid = LDAP_CONTROL_AUTHZID_RESPONSE;
143         ctrls[n]->ldctl_iscritical = 0;
144         ctrls[n]->ldctl_value.bv_len = len;
145         ctrls[n]->ldctl_value.bv_val = (char *)&ctrls[n][1];
146         if ( len ) {
147                 char *ptr;
148
149                 ptr = lutil_strcopy( ctrls[n]->ldctl_value.bv_val, "dn:" );
150                 ptr = lutil_strncopy( ptr, edn.bv_val, edn.bv_len );
151         }
152         ctrls[n]->ldctl_value.bv_val[len] = '\0';
153         ctrls[n + 1] = NULL;
154
155         rs->sr_ctrls = ctrls;
156
157         return SLAP_CB_CONTINUE;
158 }
159
160 static int
161 authzid_cleanup(
162         Operation *op,
163         SlapReply *rs )
164 {
165         if ( rs->sr_ctrls ) {
166                 LDAPControl *ctrl;
167
168                 /* if ours, cleanup */
169                 ctrl = ldap_control_find( LDAP_CONTROL_AUTHZID_RESPONSE, rs->sr_ctrls, NULL );
170                 if ( ctrl ) {
171                         op->o_tmpfree( ctrl, op->o_tmpmemctx );
172                         op->o_tmpfree( rs->sr_ctrls, op->o_tmpmemctx );
173                 }
174
175                 if ( op->o_callback->sc_private != NULL ) {
176                         rs->sr_ctrls = (LDAPControl **)op->o_callback->sc_private;
177                         op->o_callback->sc_private = NULL;
178                 }
179         }
180
181         op->o_tmpfree( op->o_callback, op->o_tmpmemctx );
182         op->o_callback = NULL;
183
184         return SLAP_CB_CONTINUE;
185 }
186
187 static int
188 authzid_op_bind(
189         Operation *op,
190         SlapReply *rs )
191 {
192         slap_callback *sc;
193
194         if ( op->o_ctrlflag[ authzid_cid ] <= SLAP_CONTROL_IGNORED ) {
195                 ConnExtraAuthzID *cex = authzid_extra_find( op->o_conn );
196                 if ( cex ) {
197                         op->o_ctrlflag[ authzid_cid ] = cex->authzid_flag;
198                 }
199         }
200
201         if ( op->o_ctrlflag[ authzid_cid ] > SLAP_CONTROL_IGNORED ) {
202                 sc = op->o_callback;
203                 op->o_callback = op->o_tmpalloc( sizeof( slap_callback ), op->o_tmpmemctx );
204                 op->o_callback->sc_response = authzid_response;
205                 op->o_callback->sc_cleanup = authzid_cleanup;
206                 op->o_callback->sc_private = NULL;
207                 op->o_callback->sc_next = sc;
208         }
209
210         return SLAP_CB_CONTINUE;
211 }
212
213 static int
214 parse_authzid_ctrl(
215         Operation       *op,
216         SlapReply       *rs,
217         LDAPControl     *ctrl )
218 {
219         if ( op->o_ctrlflag[ authzid_cid ] != SLAP_CONTROL_NONE ) {
220                 rs->sr_text = "authzid control specified multiple times";
221                 return LDAP_PROTOCOL_ERROR;
222         }
223
224         if ( !BER_BVISNULL( &ctrl->ldctl_value ) ) {
225                 rs->sr_text = "authzid control value not absent";
226                 return LDAP_PROTOCOL_ERROR;
227         }
228
229         /* drop ongoing requests */
230         (void)authzid_extra_remove( op->o_conn );
231
232         op->o_ctrlflag[ authzid_cid ] = ctrl->ldctl_iscritical ?  SLAP_CONTROL_CRITICAL : SLAP_CONTROL_NONCRITICAL;
233
234         return LDAP_SUCCESS;
235 }
236
237 static int authzid_cnt;
238
239 static int
240 authzid_db_init( BackendDB *be, ConfigReply *cr)
241 {
242         if ( authzid_cnt++ == 0 ) {
243                 int rc;
244
245                 rc = register_supported_control( LDAP_CONTROL_AUTHZID_REQUEST,
246                         SLAP_CTRL_GLOBAL|SLAP_CTRL_BIND|SLAP_CTRL_HIDE, NULL,
247                         parse_authzid_ctrl, &authzid_cid );
248                 if ( rc != LDAP_SUCCESS ) {
249                         Debug( LDAP_DEBUG_ANY,
250                                 "authzid_initialize: Failed to register control '%s' (%d)\n",
251                                 LDAP_CONTROL_AUTHZID_REQUEST, rc, 0 );
252                         return rc;
253                 }
254         }
255
256         return LDAP_SUCCESS;
257 }
258
259 static int
260 authzid_db_destroy( BackendDB *be, ConfigReply *cr )
261 {
262         assert( authzid_cnt > 0 );
263
264 #ifdef SLAP_CONFIG_DELETE
265         overlay_unregister_control( be, LDAP_CONTROL_AUTHZID_REQUEST );
266 #endif /* SLAP_CONFIG_DELETE */
267
268         if ( --authzid_cnt == 0 ) {
269                 unregister_supported_control( LDAP_CONTROL_AUTHZID_REQUEST );
270         }
271
272         return 0;
273 }
274
275 static int
276 authzid_initialize( void )
277 {
278         authzid.on_bi.bi_type = "authzid";
279
280         authzid.on_bi.bi_db_init = authzid_db_init;
281         authzid.on_bi.bi_db_destroy = authzid_db_destroy;
282         authzid.on_bi.bi_op_bind = authzid_op_bind;
283
284         return overlay_register( &authzid );
285 }
286
287 int
288 init_module( int argc, char *argv[] )
289 {
290         return authzid_initialize();
291 }
292