]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldap/extended.c
- setup framework for monitoring of back-bdb/back-hdb stuff in their
[openldap] / servers / slapd / back-ldap / extended.c
1 /* extended.c - ldap backend extended routines */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2003-2006 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 the Howard Chu for inclusion
18  * in OpenLDAP Software and subsequently enhanced by Pierangelo
19  * Masarati. 
20  */
21
22 #include "portable.h"
23
24 #include <stdio.h>
25 #include <ac/string.h>
26
27 #include "slap.h"
28 #include "back-ldap.h"
29 #include "lber_pvt.h"
30
31 static BI_op_extended ldap_back_exop_passwd;
32 static BI_op_extended ldap_back_exop_generic;
33
34 static struct exop {
35         struct berval   oid;
36         BI_op_extended  *extended;
37 } exop_table[] = {
38         { BER_BVC(LDAP_EXOP_MODIFY_PASSWD),     ldap_back_exop_passwd },
39         { BER_BVNULL, NULL }
40 };
41
42 static int
43 ldap_back_extended_one( Operation *op, SlapReply *rs, BI_op_extended exop )
44 {
45         ldapinfo_t      *li = (ldapinfo_t *) op->o_bd->be_private;
46
47         ldapconn_t      *lc;
48         LDAPControl     **oldctrls = NULL;
49         int             rc;
50
51         /* FIXME: this needs to be called here, so it is
52          * called twice; maybe we could avoid the 
53          * ldap_back_dobind() call inside each extended()
54          * call ... */
55         lc = ldap_back_getconn( op, rs, LDAP_BACK_SENDERR );
56         if ( !lc || !ldap_back_dobind( lc, op, rs, LDAP_BACK_SENDERR ) ) {
57                 return -1;
58         }
59
60         oldctrls = op->o_ctrls;
61         if ( ldap_back_proxy_authz_ctrl( &lc->lc_bound_ndn,
62                 li->li_version, &li->li_idassert, op, rs, &op->o_ctrls ) )
63         {
64                 op->o_ctrls = oldctrls;
65                 send_ldap_extended( op, rs );
66                 rs->sr_text = NULL;
67                 /* otherwise frontend resends result */
68                 rc = rs->sr_err = SLAPD_ABANDON;
69                 goto done;
70         }
71
72         rc = exop( op, rs );
73
74         if ( op->o_ctrls && op->o_ctrls != oldctrls ) {
75                 free( op->o_ctrls[ 0 ] );
76                 free( op->o_ctrls );
77         }
78         op->o_ctrls = oldctrls;
79
80 done:;
81         if ( lc != NULL ) {
82                 ldap_back_release_conn( op, rs, lc );
83         }
84                         
85         return rc;
86 }
87
88 int
89 ldap_back_extended(
90                 Operation       *op,
91                 SlapReply       *rs )
92 {
93         int     i;
94
95         for ( i = 0; exop_table[i].extended != NULL; i++ ) {
96                 if ( bvmatch( &exop_table[i].oid, &op->oq_extended.rs_reqoid ) )
97                 {
98                         return ldap_back_extended_one( op, rs, exop_table[i].extended );
99                 }
100         }
101
102         /* if we get here, the exop is known; the best that we can do
103          * is pass it thru as is */
104         /* FIXME: maybe a list of OIDs to pass thru would be safer */
105         return ldap_back_extended_one( op, rs, ldap_back_exop_generic );
106 }
107
108 static int
109 ldap_back_exop_passwd(
110                 Operation       *op,
111                 SlapReply       *rs )
112 {
113         ldapinfo_t      *li = (ldapinfo_t *) op->o_bd->be_private;
114
115         ldapconn_t      *lc;
116         req_pwdexop_s   *qpw = &op->oq_pwdexop;
117         LDAPMessage     *res;
118         ber_int_t       msgid;
119         int             rc, isproxy;
120         int             do_retry = 1;
121         char *text = NULL;
122
123         lc = ldap_back_getconn( op, rs, LDAP_BACK_SENDERR );
124         if ( !lc || !ldap_back_dobind( lc, op, rs, LDAP_BACK_SENDERR ) ) {
125                 return -1;
126         }
127
128         isproxy = ber_bvcmp( &op->o_req_ndn, &op->o_ndn );
129
130         Debug( LDAP_DEBUG_ARGS, "==> ldap_back_exop_passwd(\"%s\")%s\n",
131                 op->o_req_dn.bv_val, isproxy ? " (proxy)" : "", 0 );
132
133 retry:
134         rc = ldap_passwd( lc->lc_ld, isproxy ? &op->o_req_dn : NULL,
135                 qpw->rs_old.bv_val ? &qpw->rs_old : NULL,
136                 qpw->rs_new.bv_val ? &qpw->rs_new : NULL,
137                 op->o_ctrls, NULL, &msgid );
138
139         if ( rc == LDAP_SUCCESS ) {
140                 if ( ldap_result( lc->lc_ld, msgid, LDAP_MSG_ALL, NULL, &res ) == -1 ) {
141                         ldap_get_option( lc->lc_ld, LDAP_OPT_ERROR_NUMBER, &rc );
142                         rs->sr_err = rc;
143
144                 } else {
145                         /* only touch when activity actually took place... */
146                         if ( li->li_idle_timeout && lc ) {
147                                 lc->lc_time = op->o_time;
148                         }
149
150                         /* sigh. parse twice, because parse_passwd
151                          * doesn't give us the err / match / msg info.
152                          */
153                         rc = ldap_parse_result( lc->lc_ld, res, &rs->sr_err,
154                                         (char **)&rs->sr_matched,
155                                         &text,
156                                         NULL, NULL, 0 );
157
158                         if ( rc == LDAP_SUCCESS ) {
159                                 if ( rs->sr_err == LDAP_SUCCESS ) {
160                                         struct berval   newpw;
161
162                                         /* this never happens because 
163                                          * the frontend is generating 
164                                          * the new password, so when
165                                          * the passwd exop is proxied,
166                                          * it never delegates password
167                                          * generation to the remote server
168                                          */
169                                         rc = ldap_parse_passwd( lc->lc_ld, res,
170                                                         &newpw );
171                                         if ( rc == LDAP_SUCCESS &&
172                                                         !BER_BVISNULL( &newpw ) )
173                                         {
174                                                 rs->sr_type = REP_EXTENDED;
175                                                 rs->sr_rspdata = slap_passwd_return( &newpw );
176                                                 free( newpw.bv_val );
177                                         }
178
179                                 } else {
180                                         rc = rs->sr_err;
181                                 }
182                         }
183                         ldap_msgfree( res );
184                 }
185         }
186
187         if ( rc != LDAP_SUCCESS ) {
188                 rs->sr_err = slap_map_api2result( rs );
189                 if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) {
190                         do_retry = 0;
191                         if ( ldap_back_retry( &lc, op, rs, LDAP_BACK_SENDERR ) ) {
192                                 goto retry;
193                         }
194                 }
195
196                 if ( LDAP_BACK_QUARANTINE( li ) ) {
197                         ldap_back_quarantine( op, rs );
198                 }
199
200                 if ( text ) rs->sr_text = text;
201                 send_ldap_extended( op, rs );
202                 /* otherwise frontend resends result */
203                 rc = rs->sr_err = SLAPD_ABANDON;
204
205         } else if ( LDAP_BACK_QUARANTINE( li ) ) {
206                 ldap_back_quarantine( op, rs );
207         }
208
209         /* these have to be freed anyway... */
210         if ( rs->sr_matched ) {
211                 free( (char *)rs->sr_matched );
212                 rs->sr_matched = NULL;
213         }
214
215         if ( text ) {
216                 free( text );
217                 rs->sr_text = NULL;
218         }
219
220         if ( lc != NULL ) {
221                 ldap_back_release_conn( op, rs, lc );
222         }
223
224         return rc;
225 }
226
227 static int
228 ldap_back_exop_generic(
229         Operation       *op,
230         SlapReply       *rs )
231 {
232         ldapinfo_t      *li = (ldapinfo_t *) op->o_bd->be_private;
233
234         ldapconn_t      *lc;
235         LDAPMessage     *res;
236         ber_int_t       msgid;
237         int             rc;
238         int             do_retry = 1;
239         char *text = NULL;
240
241         lc = ldap_back_getconn( op, rs, LDAP_BACK_SENDERR );
242         if ( !lc || !ldap_back_dobind( lc, op, rs, LDAP_BACK_SENDERR ) ) {
243                 return -1;
244         }
245
246         Debug( LDAP_DEBUG_ARGS, "==> ldap_back_exop_generic(%s, \"%s\")\n",
247                 op->ore_reqoid.bv_val, op->o_req_dn.bv_val, 0 );
248
249 retry:
250         rc = ldap_extended_operation( lc->lc_ld,
251                 op->ore_reqoid.bv_val, op->ore_reqdata,
252                 op->o_ctrls, NULL, &msgid );
253
254         if ( rc == LDAP_SUCCESS ) {
255                 if ( ldap_result( lc->lc_ld, msgid, LDAP_MSG_ALL, NULL, &res ) == -1 ) {
256                         ldap_get_option( lc->lc_ld, LDAP_OPT_ERROR_NUMBER, &rc );
257                         rs->sr_err = rc;
258
259                 } else {
260                         /* only touch when activity actually took place... */
261                         if ( li->li_idle_timeout && lc ) {
262                                 lc->lc_time = op->o_time;
263                         }
264
265                         /* sigh. parse twice, because parse_passwd
266                          * doesn't give us the err / match / msg info.
267                          */
268                         rc = ldap_parse_result( lc->lc_ld, res, &rs->sr_err,
269                                         (char **)&rs->sr_matched,
270                                         &text,
271                                         NULL, NULL, 0 );
272                         if ( rc == LDAP_SUCCESS ) {
273                                 if ( rs->sr_err == LDAP_SUCCESS ) {
274                                         rc = ldap_parse_extended_result( lc->lc_ld, res,
275                                                         (char **)&rs->sr_rspoid, &rs->sr_rspdata, 0 );
276                                         if ( rc == LDAP_SUCCESS ) {
277                                                 rs->sr_type = REP_EXTENDED;
278                                         }
279
280                                 } else {
281                                         rc = rs->sr_err;
282                                 }
283                         }
284                         ldap_msgfree( res );
285                 }
286         }
287
288         if ( rc != LDAP_SUCCESS ) {
289                 rs->sr_err = slap_map_api2result( rs );
290                 if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) {
291                         do_retry = 0;
292                         if ( ldap_back_retry( &lc, op, rs, LDAP_BACK_SENDERR ) ) {
293                                 goto retry;
294                         }
295                 }
296
297                 if ( LDAP_BACK_QUARANTINE( li ) ) {
298                         ldap_back_quarantine( op, rs );
299                 }
300
301                 if ( text ) rs->sr_text = text;
302                 send_ldap_extended( op, rs );
303                 /* otherwise frontend resends result */
304                 rc = rs->sr_err = SLAPD_ABANDON;
305
306         } else if ( LDAP_BACK_QUARANTINE( li ) ) {
307                 ldap_back_quarantine( op, rs );
308         }
309
310         /* these have to be freed anyway... */
311         if ( rs->sr_matched ) {
312                 free( (char *)rs->sr_matched );
313                 rs->sr_matched = NULL;
314         }
315
316         if ( text ) {
317                 free( text );
318                 rs->sr_text = NULL;
319         }
320
321         if ( lc != NULL ) {
322                 ldap_back_release_conn( op, rs, lc );
323         }
324
325         return rc;
326 }
327