r19392: Use torture_setting_* rather than lp_parm_* where possible.
[sfrench/samba-autobuild/.git] / source4 / 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 dsdb_attribute {
36         struct dsdb_attribute *prev, *next;
37
38         const char *lDAPDisplayName;
39         const char *attributeID;
40         uint32_t attID;
41         struct GUID schemaIDGUID;
42
43         uint32_t searchFlags;
44         BOOL systemOnly;
45         uint32_t systemFlags;
46         BOOL isMemberOfPartialAttributeSet;
47
48         const char *attributeSyntax;
49         uint32_t oMSyntax;
50
51         BOOL isSingleValued;
52         uint32_t rangeLower;
53         uint32_t rangeUpper;
54
55         BOOL showInAdvancedViewOnly;
56         const char *adminDisplayName;
57         const char *adminDescription;
58 };
59
60 struct dsdb_objectClass {
61         struct dsdb_objectClass *prev, *next;
62
63         const char *subClassOf;
64
65         const char *governsID;
66         const char *rDNAttID;
67
68         BOOL showInAdvancedViewOnly;
69         const char *adminDisplayName;
70         const char *adminDescription;
71
72         uint32_t objectClassCategory;
73         const char *lDAPDisplayName;
74
75         struct GUID schemaIDGUID;
76
77         BOOL systemOnly;
78
79         const char **systemPossSuperiors;
80         const char **systemMayContain;
81
82         const char **possSuperiors;
83         const char **mayContain;
84
85         const char *defaultSecurityDescriptor;
86
87         uint32_t systemFlags;
88         BOOL defaultHidingValue;
89
90         const char *defaultObjectCategory;
91 };
92
93 struct dsdb_schema {
94         struct dsdb_attribute *attributes;
95         struct dsdb_objectClass *objectClasses;
96 };
97
98 struct test_rootDSE {
99         const char *defaultdn;
100         const char *rootdn;
101         const char *configdn;
102         const char *schemadn;
103 };
104
105 struct test_schema_ctx {
106         struct ldb_paged_control *ctrl;
107         uint32_t count;
108         BOOL pending;
109
110         int (*callback)(void *, struct ldb_context *ldb, struct ldb_message *);
111         void *private_data;
112 };
113
114 static BOOL test_search_rootDSE(struct ldb_context *ldb, struct test_rootDSE *root)
115 {
116         int ret;
117         struct ldb_message *msg;
118         struct ldb_result *r;
119
120         d_printf("Testing RootDSE Search\n");
121
122         ret = ldb_search(ldb, ldb_dn_new(ldb), LDB_SCOPE_BASE, 
123                          NULL, NULL, &r);
124         if (ret != LDB_SUCCESS) {
125                 return False;
126         } else if (r->count != 1) {
127                 talloc_free(r);
128                 return False;
129         }
130
131         msg = r->msgs[0];
132
133         root->defaultdn = ldb_msg_find_attr_as_string(msg, "defaultNamingContext", NULL);
134         talloc_steal(ldb, root->defaultdn);
135         root->rootdn    = ldb_msg_find_attr_as_string(msg, "rootDomainNamingContext", NULL);
136         talloc_steal(ldb, root->rootdn);
137         root->configdn  = ldb_msg_find_attr_as_string(msg, "configurationNamingContext", NULL);
138         talloc_steal(ldb, root->configdn);
139         root->schemadn  = ldb_msg_find_attr_as_string(msg, "schemaNamingContext", NULL);
140         talloc_steal(ldb, root->schemadn);
141
142         talloc_free(r);
143
144         return True;
145 }
146
147 static int test_schema_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
148 {
149         struct test_schema_ctx *actx = talloc_get_type(context, struct test_schema_ctx);
150         int ret = LDB_SUCCESS;
151
152         switch (ares->type) {
153         case LDB_REPLY_ENTRY:
154                 actx->count++;
155                 ret = actx->callback(actx->private_data, ldb, ares->message);
156                 break;
157
158         case LDB_REPLY_REFERRAL:
159                 break;
160
161         case LDB_REPLY_DONE:
162                 if (ares->controls) {
163                         struct ldb_paged_control *ctrl = NULL;
164                         int i;
165
166                         for (i=0; ares->controls[i]; i++) {
167                                 if (strcmp(LDB_CONTROL_PAGED_RESULTS_OID, ares->controls[i]->oid) == 0) {
168                                         ctrl = talloc_get_type(ares->controls[i]->data, struct ldb_paged_control);
169                                         break;
170                                 }
171                         }
172
173                         if (!ctrl) break;
174
175                         talloc_free(actx->ctrl->cookie);
176                         actx->ctrl->cookie = talloc_steal(actx->ctrl->cookie, ctrl->cookie);
177                         actx->ctrl->cookie_len = ctrl->cookie_len;
178
179                         if (actx->ctrl->cookie_len > 0) {
180                                 actx->pending = True;
181                         }
182                 }
183                 break;
184                 
185         default:
186                 d_printf("%s: unknown Reply Type %u\n", __location__, ares->type);
187                 return LDB_ERR_OTHER;
188         }
189
190         if (talloc_free(ares) == -1) {
191                 d_printf("talloc_free failed\n");
192                 actx->pending = 0;
193                 return LDB_ERR_OPERATIONS_ERROR;
194         }
195
196         if (ret) {
197                 return LDB_ERR_OPERATIONS_ERROR;
198         }
199
200         return LDB_SUCCESS;
201 }
202
203 static BOOL test_create_schema_type(struct ldb_context *ldb, struct test_rootDSE *root,
204                                     const char *filter,
205                                     int (*callback)(void *, struct ldb_context *ldb, struct ldb_message *),
206                                     void *private_data)
207 {
208         struct ldb_control **ctrl;
209         struct ldb_paged_control *control;
210         struct ldb_request *req;
211         int ret;
212         struct test_schema_ctx *actx;
213
214         req = talloc(ldb, struct ldb_request);
215         actx = talloc(req, struct test_schema_ctx);
216
217         ctrl = talloc_array(req, struct ldb_control *, 2);
218         ctrl[0] = talloc(ctrl, struct ldb_control);
219         ctrl[0]->oid = LDB_CONTROL_PAGED_RESULTS_OID;
220         ctrl[0]->critical = True;
221         control = talloc(ctrl[0], struct ldb_paged_control);
222         control->size = 1000;
223         control->cookie = NULL;
224         control->cookie_len = 0;
225         ctrl[0]->data = control;
226         ctrl[1] = NULL;
227
228         req->operation = LDB_SEARCH;
229         req->op.search.base = ldb_dn_explode(req, root->schemadn);
230         req->op.search.scope = LDB_SCOPE_SUBTREE;
231         req->op.search.tree = ldb_parse_tree(req, filter);
232         if (req->op.search.tree == NULL) return -1;
233         req->op.search.attrs = NULL;
234         req->controls = ctrl;
235         req->context = actx;
236         req->callback = test_schema_search_callback;
237         ldb_set_timeout(ldb, req, 0);
238
239         actx->count             = 0;
240         actx->ctrl              = control;
241         actx->callback          = callback;
242         actx->private_data      = private_data;
243 again:
244         actx->pending           = False;
245
246         ret = ldb_request(ldb, req);
247         if (ret != LDB_SUCCESS) {
248                 d_printf("search failed - %s\n", ldb_errstring(ldb));
249                 return False;
250         }
251
252         ret = ldb_wait(req->handle, LDB_WAIT_ALL);
253         if (ret != LDB_SUCCESS) {
254                 d_printf("search error - %s\n", ldb_errstring(ldb));
255                 return False;
256         }
257
258         if (actx->pending)
259                 goto again;
260
261         d_printf("filter[%s] count[%u]\n", filter, actx->count);
262         return True;
263 }
264
265 #define GET_STRING(p, elem, strict) do { \
266         (p)->elem = samdb_result_string(msg, #elem, NULL);\
267         if (strict && (p)->elem == NULL) { \
268                 d_printf("%s: %s == NULL\n", __location__, #elem); \
269                 goto failed; \
270         } \
271         (void)talloc_steal(p, (p)->elem); \
272 } while (0)
273
274 #define GET_BOOL(p, elem, strict) do { \
275         const char *str; \
276         str = samdb_result_string(msg, #elem, NULL);\
277         if (str == NULL) { \
278                 if (strict) { \
279                         d_printf("%s: %s == NULL\n", __location__, #elem); \
280                         goto failed; \
281                 } else { \
282                         (p)->elem = False; \
283                 } \
284         } else if (strcasecmp("TRUE", str) == 0) { \
285                 (p)->elem = True; \
286         } else if (strcasecmp("FALSE", str) == 0) { \
287                 (p)->elem = False; \
288         } else { \
289                 d_printf("%s: %s == %s\n", __location__, #elem, str); \
290                 goto failed; \
291         } \
292 } while (0)
293
294 #define GET_UINT32(p, elem) do { \
295         (p)->elem = samdb_result_uint(msg, #elem, 0);\
296 } while (0)
297
298 #define GET_GUID(p, elem) do { \
299         (p)->elem = samdb_result_guid(msg, #elem);\
300 } while (0)
301
302 static int test_add_attribute(void *ptr, struct ldb_context *ldb, struct ldb_message *msg)
303 {
304         struct dsdb_schema *schema = talloc_get_type(ptr, struct dsdb_schema);
305         struct dsdb_attribute *attr;
306
307         attr = talloc_zero(schema, struct dsdb_attribute);
308
309         GET_STRING(attr, lDAPDisplayName, True);
310         GET_STRING(attr, attributeID, True);
311         attr->attID = UINT32_MAX;
312         GET_GUID(attr, schemaIDGUID);
313
314         GET_UINT32(attr, searchFlags);
315         GET_BOOL(attr, systemOnly, False);
316         GET_UINT32(attr, systemFlags);
317         GET_BOOL(attr, isMemberOfPartialAttributeSet, False);
318
319         GET_STRING(attr, attributeSyntax, True);
320         GET_UINT32(attr, oMSyntax);
321
322         GET_BOOL(attr, isSingleValued, True);
323         GET_UINT32(attr, rangeLower);
324         GET_UINT32(attr, rangeUpper);
325
326         GET_BOOL(attr, showInAdvancedViewOnly, False);
327         GET_STRING(attr, adminDisplayName, True);
328         GET_STRING(attr, adminDescription, True);
329
330         DLIST_ADD_END(schema->attributes, attr, struct dsdb_attribute *);
331         return LDB_SUCCESS;
332 failed:
333         return LDB_ERR_OTHER;
334 }
335
336 static int test_add_class(void *ptr, struct ldb_context *ldb, struct ldb_message *msg)
337 {
338         struct dsdb_schema *schema = talloc_get_type(ptr, struct dsdb_schema);
339         struct dsdb_objectClass *obj;
340
341         obj = talloc_zero(schema, struct dsdb_objectClass);
342
343         GET_STRING(obj, subClassOf, True);
344
345         GET_STRING(obj, governsID, True);
346         GET_STRING(obj, rDNAttID, True);
347
348         GET_BOOL(obj, showInAdvancedViewOnly, False);
349         GET_STRING(obj, adminDisplayName, True);
350         GET_STRING(obj, adminDescription, True);
351
352         GET_UINT32(obj, objectClassCategory);
353         GET_STRING(obj, lDAPDisplayName, True);
354
355         GET_GUID(obj, schemaIDGUID);
356
357         GET_BOOL(obj, systemOnly, False);
358
359         obj->systemPossSuperiors= NULL;
360         obj->systemMayContain   = NULL;
361
362         obj->possSuperiors      = NULL;
363         obj->mayContain         = NULL;
364
365         GET_STRING(obj, defaultSecurityDescriptor, False);
366
367         GET_UINT32(obj, systemFlags);
368         GET_BOOL(obj, defaultHidingValue, True);
369
370         GET_STRING(obj, defaultObjectCategory, True);
371
372         DLIST_ADD_END(schema->objectClasses, obj, struct dsdb_objectClass *);
373         return LDB_SUCCESS;
374 failed:
375         return LDB_ERR_OTHER;
376 }
377
378 static BOOL test_create_schema(struct ldb_context *ldb, struct test_rootDSE *root, struct dsdb_schema **_schema)
379 {
380         BOOL ret = True;
381         struct dsdb_schema *schema;
382
383         schema = talloc_zero(ldb, struct dsdb_schema);
384
385         d_printf("Fetching attributes...\n");
386         ret &= test_create_schema_type(ldb, root, "(objectClass=attributeSchema)",
387                                        test_add_attribute, schema);
388         d_printf("Fetching objectClasses...\n");
389         ret &= test_create_schema_type(ldb, root, "(objectClass=classSchema)",
390                                        test_add_class, schema);
391
392         if (ret == True) {
393                 *_schema = schema;
394         }
395         return ret;
396 }
397
398 static BOOL test_dump_not_replicated(struct ldb_context *ldb, struct test_rootDSE *root, struct dsdb_schema *schema)
399 {
400         struct dsdb_attribute *a;
401         uint32_t a_i = 1;
402
403         d_printf("Dumping not replicated attributes\n");
404
405         for (a=schema->attributes; a; a = a->next) {
406                 if (!(a->systemFlags & 0x00000001)) continue;
407                 d_printf("attr[%4u]: '%s'\n", a_i++,
408                          a->lDAPDisplayName);
409         }
410
411         return True;
412 }
413
414 static BOOL test_dump_partial(struct ldb_context *ldb, struct test_rootDSE *root, struct dsdb_schema *schema)
415 {
416         struct dsdb_attribute *a;
417         uint32_t a_i = 1;
418
419         d_printf("Dumping attributes which are provided by the global catalog\n");
420
421         for (a=schema->attributes; a; a = a->next) {
422                 if (!(a->systemFlags & 0x00000002) && !a->isMemberOfPartialAttributeSet) continue;
423                 d_printf("attr[%4u]:  %u %u '%s'\n", a_i++,
424                          a->systemFlags & 0x00000002, a->isMemberOfPartialAttributeSet,
425                          a->lDAPDisplayName);
426         }
427
428         return True;
429 }
430
431 static BOOL test_dump_contructed(struct ldb_context *ldb, struct test_rootDSE *root, struct dsdb_schema *schema)
432 {
433         struct dsdb_attribute *a;
434         uint32_t a_i = 1;
435
436         d_printf("Dumping constructed attributes\n");
437
438         for (a=schema->attributes; a; a = a->next) {
439                 if (!(a->systemFlags & 0x00000004)) continue;
440                 d_printf("attr[%4u]: '%s'\n", a_i++,
441                          a->lDAPDisplayName);
442         }
443
444         return True;
445 }
446
447 static BOOL test_dump_sorted_syntax(struct ldb_context *ldb, struct test_rootDSE *root, struct dsdb_schema *schema)
448 {
449         struct dsdb_attribute *a;
450         uint32_t a_i = 1;
451         uint32_t i;
452         const char *syntaxes[] = {
453                 "2.5.5.0",
454                 "2.5.5.1",
455                 "2.5.5.2",
456                 "2.5.5.3",
457                 "2.5.5.4",
458                 "2.5.5.5",
459                 "2.5.5.6",
460                 "2.5.5.7",
461                 "2.5.5.8",
462                 "2.5.5.9",
463                 "2.5.5.10",
464                 "2.5.5.11",
465                 "2.5.5.12",
466                 "2.5.5.13",
467                 "2.5.5.14",
468                 "2.5.5.15",
469                 "2.5.5.16",
470                 "2.5.5.17"
471         };
472
473         for (i=0; i < ARRAY_SIZE(syntaxes); i++) {
474                 for (a=schema->attributes; a; a = a->next) {
475                         if (strcmp(syntaxes[i], a->attributeSyntax) != 0) continue;
476                         d_printf("attr[%4u]: %s %u '%s'\n", a_i++,
477                                  a->attributeSyntax, a->oMSyntax,
478                                  a->lDAPDisplayName);
479                 }
480         }
481
482         return True;
483 }
484
485 BOOL torture_ldap_schema(struct torture_context *torture)
486 {
487         struct ldb_context *ldb;
488         TALLOC_CTX *mem_ctx;
489         BOOL ret = True;
490         const char *host = torture_setting_string(torture, "host", NULL);
491         char *url;
492         struct test_rootDSE rootDSE;
493         struct dsdb_schema *schema = NULL;
494
495         mem_ctx = talloc_init("torture_ldap_basic");
496         ZERO_STRUCT(rootDSE);
497
498         url = talloc_asprintf(mem_ctx, "ldap://%s/", host);
499
500         ldb = ldb_wrap_connect(mem_ctx, url,
501                                NULL,
502                                cmdline_credentials,
503                                0, NULL);
504         if (!ldb) goto failed;
505
506         ret &= test_search_rootDSE(ldb, &rootDSE);
507         if (!ret) goto failed;
508         ret &= test_create_schema(ldb, &rootDSE, &schema);
509         if (!ret) goto failed;
510
511         ret &= test_dump_not_replicated(ldb, &rootDSE, schema);
512         ret &= test_dump_partial(ldb, &rootDSE, schema);
513         ret &= test_dump_contructed(ldb, &rootDSE, schema);
514         ret &= test_dump_sorted_syntax(ldb, &rootDSE, schema);
515
516 failed:
517         talloc_free(mem_ctx);
518         return ret;
519 }