~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/dsdb/samdb/ldb_modules/subtree_delete.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
   Copyright (C) Simo Sorce <idra@samba.org> 2008
 
7
 
 
8
   This program is free software; you can redistribute it and/or modify
 
9
   it under the terms of the GNU General Public License as published by
 
10
   the Free Software Foundation; either version 3 of the License, or
 
11
   (at your option) any later version.
 
12
   
 
13
   This program is distributed in the hope that it will be useful,
 
14
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
16
   GNU General Public License for more details.
 
17
   
 
18
   You should have received a copy of the GNU General Public License
 
19
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
20
*/
 
21
 
 
22
/*
 
23
 *  Name: ldb
 
24
 *
 
25
 *  Component: ldb subtree delete (prevention) module
 
26
 *
 
27
 *  Description: Prevent deletion of a subtree in LDB
 
28
 *
 
29
 *  Author: Andrew Bartlett
 
30
 */
 
31
 
 
32
#include "ldb_module.h"
 
33
 
 
34
struct subtree_delete_context {
 
35
        struct ldb_module *module;
 
36
        struct ldb_request *req;
 
37
 
 
38
        int num_children;
 
39
};
 
40
 
 
41
static struct subtree_delete_context *subdel_ctx_init(struct ldb_module *module,
 
42
                                                      struct ldb_request *req)
 
43
{
 
44
        struct ldb_context *ldb;
 
45
        struct subtree_delete_context *ac;
 
46
 
 
47
        ldb = ldb_module_get_ctx(module);
 
48
 
 
49
        ac = talloc_zero(req, struct subtree_delete_context);
 
50
        if (ac == NULL) {
 
51
                ldb_oom(ldb);
 
52
                return NULL;
 
53
        }
 
54
 
 
55
        ac->module = module;
 
56
        ac->req = req;
 
57
 
 
58
        return ac;
 
59
}
 
60
 
 
61
static int subtree_delete_search_callback(struct ldb_request *req,
 
62
                                          struct ldb_reply *ares)
 
63
{
 
64
        struct ldb_context *ldb;
 
65
        struct subtree_delete_context *ac;
 
66
        int ret;
 
67
 
 
68
        ac = talloc_get_type(req->context, struct subtree_delete_context);
 
69
        ldb = ldb_module_get_ctx(ac->module);
 
70
 
 
71
        if (!ares) {
 
72
                return ldb_module_done(ac->req, NULL, NULL,
 
73
                                        LDB_ERR_OPERATIONS_ERROR);
 
74
        }
 
75
        if (ares->error != LDB_SUCCESS) {
 
76
                return ldb_module_done(ac->req, ares->controls,
 
77
                                        ares->response, ares->error);
 
78
        }
 
79
 
 
80
        switch (ares->type) {
 
81
        case LDB_REPLY_ENTRY:
 
82
 
 
83
                talloc_free(ares);
 
84
                ac->num_children++;
 
85
                break;
 
86
 
 
87
        case LDB_REPLY_REFERRAL:
 
88
 
 
89
                /* ignore */
 
90
                talloc_free(ares);
 
91
                break;
 
92
 
 
93
        case LDB_REPLY_DONE:
 
94
 
 
95
                if (ac->num_children > 0) {
 
96
                        talloc_free(ares);
 
97
                        ldb_asprintf_errstring(ldb,
 
98
                                "Cannot delete %s, not a leaf node "
 
99
                                "(has %d children)\n",
 
100
                                ldb_dn_get_linearized(ac->req->op.del.dn),
 
101
                                ac->num_children);
 
102
                        return ldb_module_done(ac->req, NULL, NULL,
 
103
                                               LDB_ERR_NOT_ALLOWED_ON_NON_LEAF);
 
104
                }
 
105
 
 
106
                /* ok no children, let the original request through */
 
107
                ret = ldb_next_request(ac->module, ac->req);
 
108
                if (ret != LDB_SUCCESS) {
 
109
                        return ldb_module_done(ac->req, NULL, NULL, ret);
 
110
                }
 
111
 
 
112
                /* free our own context we are not going to be called back */
 
113
                talloc_free(ac);
 
114
        }
 
115
        return LDB_SUCCESS;
 
116
}
 
117
 
 
118
static int subtree_delete(struct ldb_module *module, struct ldb_request *req)
 
119
{
 
120
        struct ldb_context *ldb;
 
121
        static const char * const attrs[2] = { "distinguishedName", NULL };
 
122
        struct ldb_request *search_req;
 
123
        struct subtree_delete_context *ac;
 
124
        int ret;
 
125
        if (ldb_dn_is_special(req->op.rename.olddn)) { /* do not manipulate our control entries */
 
126
                return ldb_next_request(module, req);
 
127
        }
 
128
 
 
129
        ldb = ldb_module_get_ctx(module);
 
130
 
 
131
        /* This gets complex:  We need to:
 
132
           - Do a search for all entires under this entry 
 
133
           - Wait for these results to appear
 
134
           - In the callback for each result, count the children (if any)
 
135
           - return an error if there are any
 
136
        */
 
137
 
 
138
        ac = subdel_ctx_init(module, req);
 
139
        if (!ac) {
 
140
                return LDB_ERR_OPERATIONS_ERROR;
 
141
        }
 
142
 
 
143
        /* we do not really need to find all descendents,
 
144
         * if there is even one single direct child, that's
 
145
         * enough to bail out */
 
146
        ret = ldb_build_search_req(&search_req, ldb, ac,
 
147
                                   req->op.del.dn, LDB_SCOPE_ONELEVEL,
 
148
                                   "(objectClass=*)", attrs,
 
149
                                   req->controls,
 
150
                                   ac, subtree_delete_search_callback,
 
151
                                   req);
 
152
        if (ret != LDB_SUCCESS) {
 
153
                return ret;
 
154
        }
 
155
 
 
156
        return ldb_next_request(module, search_req);
 
157
}
 
158
 
 
159
const struct ldb_module_ops ldb_subtree_delete_module_ops = {
 
160
        .name              = "subtree_delete",
 
161
        .del               = subtree_delete,
 
162
};