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