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