Merge commit 'release-4-0-0alpha1' into v4-0-test
[ira/wip.git] / source / torture / ldap / schema.c
1 /* 
2    Unix SMB/CIFS mplementation.
3    LDAP schema tests
4    
5    Copyright (C) Stefan Metzmacher 2006
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 #include "includes.h"
23 #include "libcli/ldap/ldap_client.h"
24 #include "lib/cmdline/popt_common.h"
25 #include "db_wrap.h"
26 #include "lib/ldb/include/ldb.h"
27 #include "lib/ldb/include/ldb_errors.h"
28 #include "dsdb/samdb/samdb.h"
29 #include "lib/util/dlinklist.h"
30
31 #include "torture/torture.h"
32 #include "torture/ldap/proto.h"
33
34 #include "param/param.h"
35
36 struct test_rootDSE {
37         const char *defaultdn;
38         const char *rootdn;
39         const char *configdn;
40         const char *schemadn;
41 };
42
43 struct test_schema_ctx {
44         struct ldb_paged_control *ctrl;
45         uint32_t count;
46         bool pending;
47
48         int (*callback)(void *, struct ldb_context *ldb, struct ldb_message *);
49         void *private_data;
50 };
51
52 static bool test_search_rootDSE(struct ldb_context *ldb, struct test_rootDSE *root)
53 {
54         int ret;
55         struct ldb_message *msg;
56         struct ldb_result *r;
57
58         d_printf("Testing RootDSE Search\n");
59
60         ret = ldb_search(ldb, ldb_dn_new(ldb, ldb, NULL), LDB_SCOPE_BASE, 
61                          NULL, NULL, &r);
62         if (ret != LDB_SUCCESS) {
63                 return false;
64         } else if (r->count != 1) {
65                 talloc_free(r);
66                 return false;
67         }
68
69         msg = r->msgs[0];
70
71         root->defaultdn = ldb_msg_find_attr_as_string(msg, "defaultNamingContext", NULL);
72         talloc_steal(ldb, root->defaultdn);
73         root->rootdn    = ldb_msg_find_attr_as_string(msg, "rootDomainNamingContext", NULL);
74         talloc_steal(ldb, root->rootdn);
75         root->configdn  = ldb_msg_find_attr_as_string(msg, "configurationNamingContext", NULL);
76         talloc_steal(ldb, root->configdn);
77         root->schemadn  = ldb_msg_find_attr_as_string(msg, "schemaNamingContext", NULL);
78         talloc_steal(ldb, root->schemadn);
79
80         talloc_free(r);
81
82         return true;
83 }
84
85 static int test_schema_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
86 {
87         struct test_schema_ctx *actx = talloc_get_type(context, struct test_schema_ctx);
88         int ret = LDB_SUCCESS;
89
90         switch (ares->type) {
91         case LDB_REPLY_ENTRY:
92                 actx->count++;
93                 ret = actx->callback(actx->private_data, ldb, ares->message);
94                 break;
95
96         case LDB_REPLY_REFERRAL:
97                 break;
98
99         case LDB_REPLY_DONE:
100                 if (ares->controls) {
101                         struct ldb_paged_control *ctrl = NULL;
102                         int i;
103
104                         for (i=0; ares->controls[i]; i++) {
105                                 if (strcmp(LDB_CONTROL_PAGED_RESULTS_OID, ares->controls[i]->oid) == 0) {
106                                         ctrl = talloc_get_type(ares->controls[i]->data, struct ldb_paged_control);
107                                         break;
108                                 }
109                         }
110
111                         if (!ctrl) break;
112
113                         talloc_free(actx->ctrl->cookie);
114                         actx->ctrl->cookie = talloc_steal(actx->ctrl->cookie, ctrl->cookie);
115                         actx->ctrl->cookie_len = ctrl->cookie_len;
116
117                         if (actx->ctrl->cookie_len > 0) {
118                                 actx->pending = true;
119                         }
120                 }
121                 break;
122                 
123         default:
124                 d_printf("%s: unknown Reply Type %u\n", __location__, ares->type);
125                 return LDB_ERR_OTHER;
126         }
127
128         if (talloc_free(ares) == -1) {
129                 d_printf("talloc_free failed\n");
130                 actx->pending = 0;
131                 return LDB_ERR_OPERATIONS_ERROR;
132         }
133
134         if (ret) {
135                 return LDB_ERR_OPERATIONS_ERROR;
136         }
137
138         return LDB_SUCCESS;
139 }
140
141 static bool test_create_schema_type(struct ldb_context *ldb, struct test_rootDSE *root,
142                                     const char *filter,
143                                     int (*callback)(void *, struct ldb_context *ldb, struct ldb_message *),
144                                     void *private_data)
145 {
146         struct ldb_control **ctrl;
147         struct ldb_paged_control *control;
148         struct ldb_request *req;
149         int ret;
150         struct test_schema_ctx *actx;
151
152         req = talloc(ldb, struct ldb_request);
153         actx = talloc(req, struct test_schema_ctx);
154
155         ctrl = talloc_array(req, struct ldb_control *, 2);
156         ctrl[0] = talloc(ctrl, struct ldb_control);
157         ctrl[0]->oid = LDB_CONTROL_PAGED_RESULTS_OID;
158         ctrl[0]->critical = true;
159         control = talloc(ctrl[0], struct ldb_paged_control);
160         control->size = 1000;
161         control->cookie = NULL;
162         control->cookie_len = 0;
163         ctrl[0]->data = control;
164         ctrl[1] = NULL;
165
166         req->operation = LDB_SEARCH;
167         req->op.search.base = ldb_dn_new(req, ldb, root->schemadn);
168         req->op.search.scope = LDB_SCOPE_SUBTREE;
169         req->op.search.tree = ldb_parse_tree(req, filter);
170         if (req->op.search.tree == NULL) return -1;
171         req->op.search.attrs = NULL;
172         req->controls = ctrl;
173         req->context = actx;
174         req->callback = test_schema_search_callback;
175         ldb_set_timeout(ldb, req, 0);
176
177         actx->count             = 0;
178         actx->ctrl              = control;
179         actx->callback          = callback;
180         actx->private_data      = private_data;
181 again:
182         actx->pending           = false;
183
184         ret = ldb_request(ldb, req);
185         if (ret != LDB_SUCCESS) {
186                 d_printf("search failed - %s\n", ldb_errstring(ldb));
187                 return false;
188         }
189
190         ret = ldb_wait(req->handle, LDB_WAIT_ALL);
191         if (ret != LDB_SUCCESS) {
192                 d_printf("search error - %s\n", ldb_errstring(ldb));
193                 return false;
194         }
195
196         if (actx->pending)
197                 goto again;
198
199         d_printf("filter[%s] count[%u]\n", filter, actx->count);
200         return true;
201 }
202
203 static int test_add_attribute(void *ptr, struct ldb_context *ldb, struct ldb_message *msg)
204 {
205         struct dsdb_schema *schema = talloc_get_type(ptr, struct dsdb_schema);
206         struct dsdb_attribute *attr = NULL;
207         WERROR status;
208
209         attr = talloc_zero(schema, struct dsdb_attribute);
210         if (!attr) {
211                 goto failed;
212         }
213
214         status = dsdb_attribute_from_ldb(schema, msg, attr, attr);
215         if (!W_ERROR_IS_OK(status)) {
216                 goto failed;
217         }
218
219         DLIST_ADD_END(schema->attributes, attr, struct dsdb_attribute *);
220         return LDB_SUCCESS;
221 failed:
222         talloc_free(attr);
223         return LDB_ERR_OTHER;
224 }
225
226 static int test_add_class(void *ptr, struct ldb_context *ldb, struct ldb_message *msg)
227 {
228         struct dsdb_schema *schema = talloc_get_type(ptr, struct dsdb_schema);
229         struct dsdb_class *obj;
230         WERROR status;
231
232         obj = talloc_zero(schema, struct dsdb_class);
233         if (!obj) {
234                 goto failed;
235         }
236
237         status = dsdb_class_from_ldb(schema, msg, obj, obj);
238         if (!W_ERROR_IS_OK(status)) {
239                 goto failed;
240         }
241
242         DLIST_ADD_END(schema->classes, obj, struct dsdb_class *);
243         return LDB_SUCCESS;
244 failed:
245         return LDB_ERR_OTHER;
246 }
247
248 static bool test_create_schema(struct ldb_context *ldb, struct test_rootDSE *root, struct dsdb_schema **_schema)
249 {
250         bool ret = true;
251         struct dsdb_schema *schema;
252
253         schema = talloc_zero(ldb, struct dsdb_schema);
254
255         d_printf("Fetching attributes...\n");
256         ret &= test_create_schema_type(ldb, root, "(objectClass=attributeSchema)",
257                                        test_add_attribute, schema);
258         d_printf("Fetching objectClasses...\n");
259         ret &= test_create_schema_type(ldb, root, "(objectClass=classSchema)",
260                                        test_add_class, schema);
261
262         if (ret == true) {
263                 *_schema = schema;
264         }
265         return ret;
266 }
267
268 static bool test_dump_not_replicated(struct ldb_context *ldb, struct test_rootDSE *root, struct dsdb_schema *schema)
269 {
270         struct dsdb_attribute *a;
271         uint32_t a_i = 1;
272
273         d_printf("Dumping not replicated attributes\n");
274
275         for (a=schema->attributes; a; a = a->next) {
276                 if (!(a->systemFlags & 0x00000001)) continue;
277                 d_printf("attr[%4u]: '%s'\n", a_i++,
278                          a->lDAPDisplayName);
279         }
280
281         return true;
282 }
283
284 static bool test_dump_partial(struct ldb_context *ldb, struct test_rootDSE *root, struct dsdb_schema *schema)
285 {
286         struct dsdb_attribute *a;
287         uint32_t a_i = 1;
288
289         d_printf("Dumping attributes which are provided by the global catalog\n");
290
291         for (a=schema->attributes; a; a = a->next) {
292                 if (!(a->systemFlags & 0x00000002) && !a->isMemberOfPartialAttributeSet) continue;
293                 d_printf("attr[%4u]:  %u %u '%s'\n", a_i++,
294                          a->systemFlags & 0x00000002, a->isMemberOfPartialAttributeSet,
295                          a->lDAPDisplayName);
296         }
297
298         return true;
299 }
300
301 static bool test_dump_contructed(struct ldb_context *ldb, struct test_rootDSE *root, struct dsdb_schema *schema)
302 {
303         struct dsdb_attribute *a;
304         uint32_t a_i = 1;
305
306         d_printf("Dumping constructed attributes\n");
307
308         for (a=schema->attributes; a; a = a->next) {
309                 if (!(a->systemFlags & 0x00000004)) continue;
310                 d_printf("attr[%4u]: '%s'\n", a_i++,
311                          a->lDAPDisplayName);
312         }
313
314         return true;
315 }
316
317 static bool test_dump_sorted_syntax(struct ldb_context *ldb, struct test_rootDSE *root, struct dsdb_schema *schema)
318 {
319         struct dsdb_attribute *a;
320         uint32_t a_i = 1;
321         uint32_t i;
322         const char *syntaxes[] = {
323                 "2.5.5.0",
324                 "2.5.5.1",
325                 "2.5.5.2",
326                 "2.5.5.3",
327                 "2.5.5.4",
328                 "2.5.5.5",
329                 "2.5.5.6",
330                 "2.5.5.7",
331                 "2.5.5.8",
332                 "2.5.5.9",
333                 "2.5.5.10",
334                 "2.5.5.11",
335                 "2.5.5.12",
336                 "2.5.5.13",
337                 "2.5.5.14",
338                 "2.5.5.15",
339                 "2.5.5.16",
340                 "2.5.5.17"
341         };
342
343         d_printf("Dumping attribute syntaxes\n");
344
345         for (i=0; i < ARRAY_SIZE(syntaxes); i++) {
346                 for (a=schema->attributes; a; a = a->next) {
347                         char *om_hex;
348
349                         if (strcmp(syntaxes[i], a->attributeSyntax_oid) != 0) continue;
350
351                         om_hex = data_blob_hex_string(ldb, &a->oMObjectClass);
352                         if (!om_hex) {
353                                 return false;
354                         }
355
356                         d_printf("attr[%4u]: %s %u '%s' '%s'\n", a_i++,
357                                  a->attributeSyntax_oid, a->oMSyntax,
358                                  om_hex, a->lDAPDisplayName);
359                         talloc_free(om_hex);
360                 }
361         }
362
363         return true;
364 }
365
366 bool torture_ldap_schema(struct torture_context *torture)
367 {
368         struct ldb_context *ldb;
369         bool ret = true;
370         const char *host = torture_setting_string(torture, "host", NULL);
371         char *url;
372         struct test_rootDSE rootDSE;
373         struct dsdb_schema *schema = NULL;
374
375         ZERO_STRUCT(rootDSE);
376
377         url = talloc_asprintf(torture, "ldap://%s/", host);
378
379         ldb = ldb_wrap_connect(torture, global_loadparm, url,
380                                NULL,
381                                cmdline_credentials,
382                                0, NULL);
383         if (!ldb) goto failed;
384
385         ret &= test_search_rootDSE(ldb, &rootDSE);
386         if (!ret) goto failed;
387         ret &= test_create_schema(ldb, &rootDSE, &schema);
388         if (!ret) goto failed;
389
390         ret &= test_dump_not_replicated(ldb, &rootDSE, schema);
391         ret &= test_dump_partial(ldb, &rootDSE, schema);
392         ret &= test_dump_contructed(ldb, &rootDSE, schema);
393         ret &= test_dump_sorted_syntax(ldb, &rootDSE, schema);
394
395 failed:
396         return ret;
397 }