]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldap/extended.c
9af2738a8b5f5699da56297413de1e4469d9e448
[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                         /* sigh. parse twice, because parse_passwd
146                          * doesn't give us the err / match / msg info.
147                          */
148                         rc = ldap_parse_result( lc->lc_ld, res, &rs->sr_err,
149                                         (char **)&rs->sr_matched,
150                                         &text,
151                                         NULL, NULL, 0 );
152
153                         if ( rc == LDAP_SUCCESS ) {
154                                 if ( rs->sr_err == LDAP_SUCCESS ) {
155                                         struct berval   newpw;
156
157                                         /* this never happens because 
158                                          * the frontend is generating 
159                                          * the new password, so when
160                                          * the passwd exop is proxied,
161                                          * it never delegates password
162                                          * generation to the remote server
163                                          */
164                                         rc = ldap_parse_passwd( lc->lc_ld, res,
165                                                         &newpw );
166                                         if ( rc == LDAP_SUCCESS &&
167                                                         !BER_BVISNULL( &newpw ) )
168                                         {
169                                                 rs->sr_type = REP_EXTENDED;
170                                                 rs->sr_rspdata = slap_passwd_return( &newpw );
171                                                 free( newpw.bv_val );
172                                         }
173
174                                 } else {
175                                         rc = rs->sr_err;
176                                 }
177                         }
178                         ldap_msgfree( res );
179                 }
180         }
181
182         if ( rc != LDAP_SUCCESS ) {
183                 rs->sr_err = slap_map_api2result( rs );
184                 if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) {
185                         do_retry = 0;
186                         if ( ldap_back_retry( &lc, op, rs, LDAP_BACK_SENDERR ) ) {
187                                 goto retry;
188                         }
189                 }
190
191                 if ( LDAP_BACK_QUARANTINE( li ) ) {
192                         ldap_back_quarantine( op, rs );
193                 }
194
195                 if ( text ) rs->sr_text = text;
196                 send_ldap_extended( op, rs );
197                 /* otherwise frontend resends result */
198                 rc = rs->sr_err = SLAPD_ABANDON;
199
200         } else if ( LDAP_BACK_QUARANTINE( li ) ) {
201                 ldap_back_quarantine( op, rs );
202         }
203
204         /* these have to be freed anyway... */
205         if ( rs->sr_matched ) {
206                 free( (char *)rs->sr_matched );
207                 rs->sr_matched = NULL;
208         }
209
210         if ( text ) {
211                 free( text );
212                 rs->sr_text = NULL;
213         }
214
215         if ( lc != NULL ) {
216                 ldap_back_release_conn( op, rs, lc );
217         }
218
219         return rc;
220 }
221
222 static int
223 ldap_back_exop_generic(
224         Operation       *op,
225         SlapReply       *rs )
226 {
227         ldapinfo_t      *li = (ldapinfo_t *) op->o_bd->be_private;
228
229         ldapconn_t      *lc;
230         LDAPMessage     *res;
231         ber_int_t       msgid;
232         int             rc;
233         int             do_retry = 1;
234         char *text = NULL;
235
236         lc = ldap_back_getconn( op, rs, LDAP_BACK_SENDERR );
237         if ( !lc || !ldap_back_dobind( lc, op, rs, LDAP_BACK_SENDERR ) ) {
238                 return -1;
239         }
240
241         Debug( LDAP_DEBUG_ARGS, "==> ldap_back_exop_generic(%s, \"%s\")\n",
242                 op->ore_reqoid.bv_val, op->o_req_dn.bv_val, 0 );
243
244 retry:
245         rc = ldap_extended_operation( lc->lc_ld,
246                 op->ore_reqoid.bv_val, op->ore_reqdata,
247                 op->o_ctrls, NULL, &msgid );
248
249         if ( rc == LDAP_SUCCESS ) {
250                 if ( ldap_result( lc->lc_ld, msgid, LDAP_MSG_ALL, NULL, &res ) == -1 ) {
251                         ldap_get_option( lc->lc_ld, LDAP_OPT_ERROR_NUMBER, &rc );
252                         rs->sr_err = rc;
253
254                 } else {
255                         /* sigh. parse twice, because parse_passwd
256                          * doesn't give us the err / match / msg info.
257                          */
258                         rc = ldap_parse_result( lc->lc_ld, res, &rs->sr_err,
259                                         (char **)&rs->sr_matched,
260                                         &text,
261                                         NULL, NULL, 0 );
262                         if ( rc == LDAP_SUCCESS ) {
263                                 if ( rs->sr_err == LDAP_SUCCESS ) {
264                                         rc = ldap_parse_extended_result( lc->lc_ld, res,
265                                                         (char **)&rs->sr_rspoid, &rs->sr_rspdata, 0 );
266                                         if ( rc == LDAP_SUCCESS ) {
267                                                 rs->sr_type = REP_EXTENDED;
268                                         }
269
270                                 } else {
271                                         rc = rs->sr_err;
272                                 }
273                         }
274                         ldap_msgfree( res );
275                 }
276         }
277
278         if ( rc != LDAP_SUCCESS ) {
279                 rs->sr_err = slap_map_api2result( rs );
280                 if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) {
281                         do_retry = 0;
282                         if ( ldap_back_retry( &lc, op, rs, LDAP_BACK_SENDERR ) ) {
283                                 goto retry;
284                         }
285                 }
286
287                 if ( LDAP_BACK_QUARANTINE( li ) ) {
288                         ldap_back_quarantine( op, rs );
289                 }
290
291                 if ( text ) rs->sr_text = text;
292                 send_ldap_extended( op, rs );
293                 /* otherwise frontend resends result */
294                 rc = rs->sr_err = SLAPD_ABANDON;
295
296         } else if ( LDAP_BACK_QUARANTINE( li ) ) {
297                 ldap_back_quarantine( op, rs );
298         }
299
300         /* these have to be freed anyway... */
301         if ( rs->sr_matched ) {
302                 free( (char *)rs->sr_matched );
303                 rs->sr_matched = NULL;
304         }
305
306         if ( text ) {
307                 free( text );
308                 rs->sr_text = NULL;
309         }
310
311         if ( lc != NULL ) {
312                 ldap_back_release_conn( op, rs, lc );
313         }
314
315         return rc;
316 }
317