]> git.sur5r.net Git - openldap/blob - servers/slapd/controls.c
error message from be_entry_put tool backend function
[openldap] / servers / slapd / controls.c
1 /* $OpenLDAP$ */
2 /* 
3  * Copyright 1999-2002 The OpenLDAP Foundation.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms are permitted only
7  * as authorized by the OpenLDAP Public License.  A copy of this
8  * license is available at http://www.OpenLDAP.org/license.html or
9  * in file LICENSE in the top-level directory of the distribution.
10  */
11 #include "portable.h"
12
13 #include <stdio.h>
14
15 #include <ac/string.h>
16 #include <ac/socket.h>
17
18 #include "slap.h"
19
20 #include "../../libraries/liblber/lber-int.h"
21
22 #define SLAP_CTRL_ABANDON       0x0001
23 #define SLAP_CTRL_ADD           0x2002
24 #define SLAP_CTRL_BIND          0x0004
25 #define SLAP_CTRL_COMPARE       0x1008
26 #define SLAP_CTRL_DELETE        0x2010
27 #define SLAP_CTRL_MODIFY        0x2020
28 #define SLAP_CTRL_RENAME        0x2040
29 #define SLAP_CTRL_SEARCH        0x1080
30 #define SLAP_CTRL_UNBIND        0x0100
31
32 #define SLAP_CTRL_INTROGATE     (SLAP_CTRL_COMPARE|SLAP_CTRL_SEARCH)
33 #define SLAP_CTRL_UPDATE \
34         (SLAP_CTRL_ADD|SLAP_CTRL_DELETE|SLAP_CTRL_MODIFY|SLAP_CTRL_RENAME)
35 #define SLAP_CTRL_ACCESS        (SLAP_CTRL_INTROGATE|SLAP_CTRL_UPDATE)
36
37 typedef int (SLAP_CTRL_PARSE_FN) LDAP_P((
38         Connection *conn,
39         Operation *op,
40         LDAPControl *ctrl,
41         const char **text ));
42
43 static SLAP_CTRL_PARSE_FN parseManageDSAit;
44 static SLAP_CTRL_PARSE_FN parseSubentries;
45
46 static struct slap_control {
47         char *sc_oid;
48         int sc_ops_mask;
49         char **sc_extendedops;
50         SLAP_CTRL_PARSE_FN *sc_parse;
51
52 } supportedControls[] = {
53         { LDAP_CONTROL_MANAGEDSAIT,
54                 SLAP_CTRL_ACCESS, NULL,
55                 parseManageDSAit },
56         { LDAP_CONTROL_SUBENTRIES,
57                 SLAP_CTRL_SEARCH, NULL,
58                 parseSubentries },
59         { NULL }
60 };
61
62 char *
63 get_supported_ctrl(int index)
64 {
65         return supportedControls[index].sc_oid;
66 }
67
68 static struct slap_control *
69 find_ctrl( const char *oid )
70 {
71         int i;
72         for( i=0; supportedControls[i].sc_oid; i++ ) {
73                 if( strcmp( oid, supportedControls[i].sc_oid ) == 0 ) {
74                         return &supportedControls[i];
75                 }
76         }
77         return NULL;
78 }
79
80 int get_ctrls(
81         Connection *conn,
82         Operation *op,
83         int sendres )
84 {
85         int nctrls = 0;
86         ber_tag_t tag;
87         ber_len_t len;
88         char *opaque;
89         BerElement *ber = op->o_ber;
90         LDAPControl ***ctrls = &op->o_ctrls;
91         struct slap_control *c;
92         int rc = LDAP_SUCCESS;
93         const char *errmsg = NULL;
94
95         len = ber_pvt_ber_remaining(ber);
96
97         if( len == 0) {
98                 /* no controls */
99                 rc = LDAP_SUCCESS;
100                 return rc;
101         }
102
103         if(( tag = ber_peek_tag( ber, &len )) != LDAP_TAG_CONTROLS ) {
104                 if( tag == LBER_ERROR ) {
105                         rc = SLAPD_DISCONNECT;
106                         errmsg = "unexpected data in PDU";
107                 }
108
109                 goto return_results;
110         }
111
112 #ifdef NEW_LOGGING
113         LDAP_LOG(( "operation", LDAP_LEVEL_ENTRY,
114                 "get_ctrls: conn %d\n", conn->c_connid ));
115 #else
116         Debug( LDAP_DEBUG_TRACE, "=> get_ctrls\n", 0, 0, 0 );
117 #endif
118         if( op->o_protocol < LDAP_VERSION3 ) {
119                 rc = SLAPD_DISCONNECT;
120                 errmsg = "controls require LDAPv3";
121                 goto return_results;
122         }
123
124         /* set through each element */
125         *ctrls = ch_malloc( 1 * sizeof(LDAPControl *) );
126
127 #if 0
128         if( *ctrls == NULL ) {
129                 rc = LDAP_NO_MEMORY;
130                 errmsg = "no memory";
131                 goto return_results;
132         }
133 #endif
134
135         *ctrls[nctrls] = NULL;
136
137         for( tag = ber_first_element( ber, &len, &opaque );
138                 tag != LBER_ERROR;
139                 tag = ber_next_element( ber, &len, opaque ) )
140         {
141                 LDAPControl *tctrl;
142                 LDAPControl **tctrls;
143
144                 tctrl = ch_calloc( 1, sizeof(LDAPControl) );
145                 tctrl->ldctl_oid = NULL;
146                 tctrl->ldctl_value.bv_val = NULL;
147
148                 /* allocate pointer space for current controls (nctrls)
149                  * + this control + extra NULL
150                  */
151                 tctrls = (tctrl == NULL) ? NULL :
152                         ch_realloc(*ctrls, (nctrls+2) * sizeof(LDAPControl *));
153
154 #if 0
155                 if( tctrls == NULL ) {
156                         /* one of the above allocation failed */
157
158                         if( tctrl != NULL ) {
159                                 ch_free( tctrl );
160                         }
161
162                         ldap_controls_free(*ctrls);
163                         *ctrls = NULL;
164
165                         rc = LDAP_NO_MEMORY;
166                         errmsg = "no memory";
167                         goto return_results;
168                 }
169 #endif
170
171                 tctrls[nctrls++] = tctrl;
172                 tctrls[nctrls] = NULL;
173
174                 tag = ber_scanf( ber, "{a" /*}*/, &tctrl->ldctl_oid );
175
176                 if( tag == LBER_ERROR ) {
177 #ifdef NEW_LOGGING
178                         LDAP_LOG(( "operation", LDAP_LEVEL_INFO,
179                                 "get_ctrls: conn %d  get OID failed.\n",
180                                 conn->c_connid ));
181 #else
182                         Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: get oid failed.\n",
183                                 0, 0, 0 );
184 #endif
185                         *ctrls = NULL;
186                         ldap_controls_free( tctrls );
187                         rc = SLAPD_DISCONNECT;
188                         errmsg = "decoding controls error";
189                         goto return_results;
190                 }
191
192                 tag = ber_peek_tag( ber, &len );
193
194                 if( tag == LBER_BOOLEAN ) {
195                         ber_int_t crit;
196                         tag = ber_scanf( ber, "b", &crit );
197
198                         if( tag == LBER_ERROR ) {
199 #ifdef NEW_LOGGING
200                                 LDAP_LOG(( "operation", LDAP_LEVEL_INFO,
201                                         "get_ctrls: conn %d  get crit failed.\n",
202                                         conn->c_connid ));
203 #else
204                                 Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: get crit failed.\n",
205                                         0, 0, 0 );
206 #endif
207                                 *ctrls = NULL;
208                                 ldap_controls_free( tctrls );
209                                 rc = SLAPD_DISCONNECT;
210                                 errmsg = "decoding controls error";
211                                 goto return_results;
212                         }
213
214                         tctrl->ldctl_iscritical = (crit != 0);
215                         tag = ber_peek_tag( ber, &len );
216                 }
217
218 #ifdef NEW_LOGGING
219                 LDAP_LOG(( "operation", LDAP_LEVEL_INFO,
220                         "get_ctrls: conn %d oid=\"%s\" (%scritical)\n",
221                         conn->c_connid, tctrl->ldctl_oid,
222                         tctrl->ldctl_iscritical ? "" : "non" ));
223 #else
224                 Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: oid=\"%s\" (%scritical)\n",
225                         tctrl->ldctl_oid, 
226                         tctrl->ldctl_iscritical ? "" : "non",
227                         0 );
228 #endif
229                 if( tag == LBER_OCTETSTRING ) {
230                         tag = ber_scanf( ber, "o", &tctrl->ldctl_value );
231
232                         if( tag == LBER_ERROR ) {
233 #ifdef NEW_LOGGING
234                                 LDAP_LOG(( "operation", LDAP_LEVEL_INFO,
235                                         "get_ctrls: conn %d  get value failed.\n", conn->c_connid ));
236 #else
237                                 Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: get value failed.\n",
238                                         0, 0, 0 );
239 #endif
240                                 *ctrls = NULL;
241                                 ldap_controls_free( tctrls );
242                                 rc = SLAPD_DISCONNECT;
243                                 errmsg = "decoding controls error";
244                                 goto return_results;
245                         }
246                 }
247
248                 c = find_ctrl( tctrl->ldctl_oid );
249                 if( c != NULL ) {
250                         /* recongized control */
251                         int tagmask = -1;
252                         switch( op->o_tag ) {
253                         case LDAP_REQ_ADD:
254                                 tagmask = SLAP_CTRL_ADD;
255                                 break;
256                         case LDAP_REQ_BIND:
257                                 tagmask = SLAP_CTRL_BIND;
258                                 break;
259                         case LDAP_REQ_COMPARE:
260                                 tagmask = SLAP_CTRL_COMPARE;
261                                 break;
262                         case LDAP_REQ_DELETE:
263                                 tagmask = SLAP_CTRL_DELETE;
264                                 break;
265                         case LDAP_REQ_MODIFY:
266                                 tagmask = SLAP_CTRL_MODIFY;
267                                 break;
268                         case LDAP_REQ_RENAME:
269                                 tagmask = SLAP_CTRL_RENAME;
270                                 break;
271                         case LDAP_REQ_SEARCH:
272                                 tagmask = SLAP_CTRL_SEARCH;
273                                 break;
274                         case LDAP_REQ_UNBIND:
275                                 tagmask = SLAP_CTRL_UNBIND;
276                                 break;
277                         case LDAP_REQ_EXTENDED:
278                                 /* FIXME: check list of extended operations */
279                                 tagmask = -1;
280                                 break;
281                         default:
282                                 rc = LDAP_OTHER;
283                                 errmsg = "controls internal error";
284                                 goto return_results;
285                         }
286
287                         if (( c->sc_ops_mask & tagmask ) == tagmask ) {
288                                 /* available extension */
289
290                                 if( !c->sc_parse ) {
291                                         rc = LDAP_OTHER;
292                                         errmsg = "not yet implemented";
293                                         goto return_results;
294                                 }
295
296                                 rc = c->sc_parse( conn, op, tctrl, &errmsg );
297
298                                 if( rc != LDAP_SUCCESS ) goto return_results;
299
300                         } else if( tctrl->ldctl_iscritical ) {
301                                 /* unavailable CRITICAL control */
302                                 rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
303                                 errmsg = "critical extension is unavailable";
304                                 goto return_results;
305                         }
306
307                 } else if( tctrl->ldctl_iscritical ) {
308                         /* unrecongized CRITICAL control */
309                         rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
310                         errmsg = "critical extension is not recongized";
311                         goto return_results;
312                 }
313
314                 *ctrls = tctrls;
315         }
316
317 return_results:
318 #ifdef NEW_LOGGING
319         LDAP_LOG(( "operation", LDAP_LEVEL_RESULTS,
320                 "get_ctrls: conn %d     %d %d %s\n",
321                 conn->c_connid, nctrls, rc, errmsg ? errmsg : "" ));
322 #else
323         Debug( LDAP_DEBUG_TRACE, "<= get_ctrls: %d %d %s\n",
324                 nctrls, rc, errmsg ? errmsg : "");
325 #endif
326
327         if( sendres && rc != LDAP_SUCCESS ) {
328                 if( rc == SLAPD_DISCONNECT ) {
329                         send_ldap_disconnect( conn, op, LDAP_PROTOCOL_ERROR, errmsg );
330                 } else {
331                         send_ldap_result( conn, op, rc,
332                                 NULL, errmsg, NULL, NULL );
333                 }
334         }
335
336         return rc;
337 }
338
339 static int parseManageDSAit (
340         Connection *conn,
341         Operation *op,
342         LDAPControl *ctrl,
343         const char **text )
344 {
345         if ( op->o_managedsait != SLAP_NO_CONTROL ) {
346                 *text = "manageDSAit control specified multiple times";
347                 return LDAP_PROTOCOL_ERROR;
348         }
349
350         if ( ctrl->ldctl_value.bv_len ) {
351                 *text = "manageDSAit control value not empty";
352                 return LDAP_PROTOCOL_ERROR;
353         }
354
355         op->o_managedsait = ctrl->ldctl_iscritical
356                 ? SLAP_CRITICAL_CONTROL
357                 : SLAP_NONCRITICAL_CONTROL;
358
359         return LDAP_SUCCESS;
360 }
361
362 static int parseSubentries (
363         Connection *conn,
364         Operation *op,
365         LDAPControl *ctrl,
366         const char **text )
367 {
368         if ( op->o_subentries != SLAP_NO_CONTROL ) {
369                 *text = "subentries control specified multiple times";
370                 return LDAP_PROTOCOL_ERROR;
371         }
372
373         /* FIXME: should use BER library */
374         if( ( ctrl->ldctl_value.bv_len != 3 )
375                 && ( ctrl->ldctl_value.bv_val[0] != 0x01 )
376                 && ( ctrl->ldctl_value.bv_val[1] != 0x01 ))
377         {
378                 *text = "subentries control value encoding is bogus";
379                 return LDAP_PROTOCOL_ERROR;
380         }
381
382         op->o_subentries = ctrl->ldctl_iscritical
383                 ? SLAP_CRITICAL_CONTROL
384                 : SLAP_NONCRITICAL_CONTROL;
385
386         op->o_subentries_visibility = (ctrl->ldctl_value.bv_val[2] != 0x00);
387
388         return LDAP_SUCCESS;
389 }