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