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