~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/dsdb/samdb/ldb_modules/subtree_rename.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
   ldb database library
 
3
 
 
4
   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006-2007
 
5
   Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
 
6
 
 
7
   This program is free software; you can redistribute it and/or modify
 
8
   it under the terms of the GNU General Public License as published by
 
9
   the Free Software Foundation; either version 3 of the License, or
 
10
   (at your option) any later version.
 
11
   
 
12
   This program is distributed in the hope that it will be useful,
 
13
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
   GNU General Public License for more details.
 
16
   
 
17
   You should have received a copy of the GNU General Public License
 
18
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
19
*/
 
20
 
 
21
/*
 
22
 *  Name: ldb
 
23
 *
 
24
 *  Component: ldb subtree rename module
 
25
 *
 
26
 *  Description: Rename a subtree in LDB
 
27
 *
 
28
 *  Author: Andrew Bartlett
 
29
 */
 
30
 
 
31
#include "ldb_module.h"
 
32
 
 
33
struct subren_msg_store {
 
34
        struct subren_msg_store *next;
 
35
        struct ldb_dn *olddn;
 
36
        struct ldb_dn *newdn;
 
37
};
 
38
 
 
39
struct subtree_rename_context {
 
40
        struct ldb_module *module;
 
41
        struct ldb_request *req;
 
42
 
 
43
        struct subren_msg_store *list;
 
44
        struct subren_msg_store *current;
 
45
};
 
46
 
 
47
static struct subtree_rename_context *subren_ctx_init(struct ldb_module *module,
 
48
                                         struct ldb_request *req)
 
49
{
 
50
        struct ldb_context *ldb;
 
51
        struct subtree_rename_context *ac;
 
52
 
 
53
        ldb = ldb_module_get_ctx(module);
 
54
 
 
55
        ac = talloc_zero(req, struct subtree_rename_context);
 
56
        if (ac == NULL) {
 
57
                ldb_oom(ldb);
 
58
                return NULL;
 
59
        }
 
60
 
 
61
        ac->module = module;
 
62
        ac->req = req;
 
63
 
 
64
        return ac;
 
65
}
 
66
 
 
67
static int subtree_rename_next_request(struct subtree_rename_context *ac);
 
68
 
 
69
static int subtree_rename_callback(struct ldb_request *req,
 
70
                                   struct ldb_reply *ares)
 
71
{
 
72
        struct ldb_context *ldb;
 
73
        struct subtree_rename_context *ac;
 
74
        int ret;
 
75
 
 
76
        ac = talloc_get_type(req->context, struct subtree_rename_context);
 
77
        ldb = ldb_module_get_ctx(ac->module);
 
78
 
 
79
        if (!ares) {
 
80
                return ldb_module_done(ac->req, NULL, NULL,
 
81
                                        LDB_ERR_OPERATIONS_ERROR);
 
82
        }
 
83
 
 
84
        if (ares->error != LDB_SUCCESS) {
 
85
                return ldb_module_done(ac->req, ares->controls,
 
86
                                        ares->response, ares->error);
 
87
        }
 
88
 
 
89
        if (ares->type != LDB_REPLY_DONE) {
 
90
                ldb_set_errstring(ldb, "Invalid reply type!\n");
 
91
                return ldb_module_done(ac->req, NULL, NULL,
 
92
                                        LDB_ERR_OPERATIONS_ERROR);
 
93
        }
 
94
 
 
95
        if (ac->current == NULL) {
 
96
                /* this was the last one */
 
97
                return ldb_module_done(ac->req, ares->controls,
 
98
                                        ares->response, LDB_SUCCESS);
 
99
        }
 
100
 
 
101
        ret = subtree_rename_next_request(ac);
 
102
        if (ret != LDB_SUCCESS) {
 
103
                return ldb_module_done(ac->req, NULL, NULL, ret);
 
104
        }
 
105
 
 
106
        talloc_free(ares);
 
107
        return LDB_SUCCESS;
 
108
}
 
109
 
 
110
static int subtree_rename_next_request(struct subtree_rename_context *ac)
 
111
{
 
112
        struct ldb_context *ldb;
 
113
        struct ldb_request *req;
 
114
        int ret;
 
115
 
 
116
        ldb = ldb_module_get_ctx(ac->module);
 
117
 
 
118
        if (ac->current == NULL) {
 
119
                return LDB_ERR_OPERATIONS_ERROR;
 
120
        }
 
121
 
 
122
        ret = ldb_build_rename_req(&req, ldb, ac->current,
 
123
                                   ac->current->olddn,
 
124
                                   ac->current->newdn,
 
125
                                   ac->req->controls,
 
126
                                   ac, subtree_rename_callback,
 
127
                                   ac->req);
 
128
        if (ret != LDB_SUCCESS) {
 
129
                return ret;
 
130
        }
 
131
 
 
132
        ac->current = ac->current->next;
 
133
 
 
134
        return ldb_next_request(ac->module, req);
 
135
}
 
136
 
 
137
static int subtree_rename_search_callback(struct ldb_request *req,
 
138
                                          struct ldb_reply *ares)
 
139
{
 
140
        struct subren_msg_store *store;
 
141
        struct subtree_rename_context *ac;
 
142
        int ret;
 
143
 
 
144
        ac = talloc_get_type(req->context, struct subtree_rename_context);
 
145
 
 
146
        if (!ares || !ac->current) {
 
147
                return ldb_module_done(ac->req, NULL, NULL,
 
148
                                        LDB_ERR_OPERATIONS_ERROR);
 
149
        }
 
150
        if (ares->error != LDB_SUCCESS) {
 
151
                return ldb_module_done(ac->req, ares->controls,
 
152
                                        ares->response, ares->error);
 
153
        }
 
154
 
 
155
        switch (ares->type) {
 
156
        case LDB_REPLY_ENTRY:
 
157
 
 
158
                if (ldb_dn_compare(ares->message->dn, ac->list->olddn) == 0) {
 
159
                        /* this was already stored by the
 
160
                         * subtree_rename_search() */
 
161
                        talloc_free(ares);
 
162
                        return LDB_SUCCESS;
 
163
                }
 
164
 
 
165
                store = talloc_zero(ac, struct subren_msg_store);
 
166
                if (store == NULL) {
 
167
                        return ldb_module_done(ac->req, NULL, NULL,
 
168
                                                LDB_ERR_OPERATIONS_ERROR);
 
169
                }
 
170
                ac->current->next = store;
 
171
                ac->current = store;
 
172
 
 
173
                /* the first list element contains the base for the rename */
 
174
                store->olddn = talloc_steal(store, ares->message->dn);
 
175
                store->newdn = ldb_dn_copy(store, store->olddn);
 
176
 
 
177
                if ( ! ldb_dn_remove_base_components(store->newdn,
 
178
                                ldb_dn_get_comp_num(ac->list->olddn))) {
 
179
                        return ldb_module_done(ac->req, NULL, NULL,
 
180
                                                LDB_ERR_OPERATIONS_ERROR);
 
181
                }
 
182
 
 
183
                if ( ! ldb_dn_add_base(store->newdn, ac->list->newdn)) {
 
184
                        return ldb_module_done(ac->req, NULL, NULL,
 
185
                                                LDB_ERR_OPERATIONS_ERROR);
 
186
                }
 
187
 
 
188
                break;
 
189
 
 
190
        case LDB_REPLY_REFERRAL:
 
191
                /* ignore */
 
192
                break;
 
193
 
 
194
        case LDB_REPLY_DONE:
 
195
 
 
196
                /* rewind ac->current */
 
197
                ac->current = ac->list;
 
198
 
 
199
                /* All dns set up, start with the first one */
 
200
                ret = subtree_rename_next_request(ac);
 
201
 
 
202
                if (ret != LDB_SUCCESS) {
 
203
                        return ldb_module_done(ac->req, NULL, NULL, ret);
 
204
                }
 
205
                break;
 
206
        }
 
207
 
 
208
        talloc_free(ares);
 
209
        return LDB_SUCCESS;
 
210
}
 
211
 
 
212
/* rename */
 
213
static int subtree_rename(struct ldb_module *module, struct ldb_request *req)
 
214
{
 
215
        struct ldb_context *ldb;
 
216
        static const char *attrs[2] = { "distinguishedName", NULL };
 
217
        struct ldb_request *search_req;
 
218
        struct subtree_rename_context *ac;
 
219
        int ret;
 
220
        if (ldb_dn_is_special(req->op.rename.olddn)) { /* do not manipulate our control entries */
 
221
                return ldb_next_request(module, req);
 
222
        }
 
223
 
 
224
        ldb = ldb_module_get_ctx(module);
 
225
 
 
226
        /* This gets complex:  We need to:
 
227
           - Do a search for all entires under this entry 
 
228
           - Wait for these results to appear
 
229
           - In the callback for each result, issue a modify request
 
230
            - That will include this rename, we hope
 
231
           - Wait for each modify result
 
232
           - Regain our sainity 
 
233
        */
 
234
 
 
235
        ac = subren_ctx_init(module, req);
 
236
        if (!ac) {
 
237
                return LDB_ERR_OPERATIONS_ERROR;
 
238
        }
 
239
 
 
240
        /* add this entry as the first to do */
 
241
        ac->current = talloc_zero(ac, struct subren_msg_store);
 
242
        if (ac->current == NULL) {
 
243
                return LDB_ERR_OPERATIONS_ERROR;
 
244
        }
 
245
        ac->current->olddn = req->op.rename.olddn;
 
246
        ac->current->newdn = req->op.rename.newdn;
 
247
        ac->list = ac->current;
 
248
 
 
249
        ret = ldb_build_search_req(&search_req, ldb, ac,
 
250
                                   req->op.rename.olddn, 
 
251
                                   LDB_SCOPE_SUBTREE,
 
252
                                   "(objectClass=*)",
 
253
                                   attrs,
 
254
                                   NULL,
 
255
                                   ac, 
 
256
                                   subtree_rename_search_callback,
 
257
                                   req);
 
258
        if (ret != LDB_SUCCESS) {
 
259
                return ret;
 
260
        }
 
261
 
 
262
        return ldb_next_request(module, search_req);
 
263
}
 
264
 
 
265
const struct ldb_module_ops ldb_subtree_rename_module_ops = {
 
266
        .name              = "subtree_rename",
 
267
        .rename            = subtree_rename,
 
268
};