s4: popt: Global replace of cmdline_credentials -> popt_get_cmdline_credentials().
[gd/samba-autobuild/.git] / source4 / torture / ldap / basic.c
1 /* 
2    Unix SMB/CIFS mplementation.
3    LDAP protocol helper functions for SAMBA
4    
5    Copyright (C) Stefan Metzmacher 2004
6    Copyright (C) Simo Sorce 2004
7    Copyright (C) Matthias Dieter Wallnöfer 2009-2010
8     
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21    
22 */
23
24 #include "includes.h"
25 #include "ldb_wrap.h"
26 #include "libcli/ldap/ldap_client.h"
27 #include "lib/cmdline/popt_common.h"
28
29 #include "torture/torture.h"
30 #include "torture/ldap/proto.h"
31
32
33 static bool test_bind_simple(struct ldap_connection *conn, const char *userdn, const char *password)
34 {
35         NTSTATUS status;
36         bool ret = true;
37
38         status = torture_ldap_bind(conn, userdn, password);
39         if (!NT_STATUS_IS_OK(status)) {
40                 ret = false;
41         }
42
43         return ret;
44 }
45
46 static bool test_bind_sasl(struct torture_context *tctx,
47                            struct ldap_connection *conn, struct cli_credentials *creds)
48 {
49         NTSTATUS status;
50         bool ret = true;
51
52         printf("Testing sasl bind as user\n");
53
54         status = torture_ldap_bind_sasl(conn, creds, tctx->lp_ctx);
55         if (!NT_STATUS_IS_OK(status)) {
56                 ret = false;
57         }
58
59         return ret;
60 }
61
62 static bool test_multibind(struct ldap_connection *conn, const char *userdn, const char *password)
63 {
64         bool ret = true;
65
66         printf("Testing multiple binds on a single connection as anonymous and user\n");
67
68         ret = test_bind_simple(conn, NULL, NULL);
69         if (!ret) {
70                 printf("1st bind as anonymous failed\n");
71                 return ret;
72         }
73
74         ret = test_bind_simple(conn, userdn, password);
75         if (!ret) {
76                 printf("2nd bind as authenticated user failed\n");
77         }
78
79         return ret;
80 }
81
82 static bool test_search_rootDSE(struct ldap_connection *conn, const char **basedn,
83         const char ***partitions)
84 {
85         bool ret = true;
86         struct ldap_message *msg, *result;
87         struct ldap_request *req;
88         int i;
89         struct ldap_SearchResEntry *r;
90         NTSTATUS status;
91
92         printf("Testing RootDSE Search\n");
93
94         *basedn = NULL;
95
96         if (partitions != NULL) {
97                 *partitions = const_str_list(str_list_make_empty(conn));
98         }
99
100         msg = new_ldap_message(conn);
101         if (!msg) {
102                 return false;
103         }
104
105         msg->type = LDAP_TAG_SearchRequest;
106         msg->r.SearchRequest.basedn = "";
107         msg->r.SearchRequest.scope = LDAP_SEARCH_SCOPE_BASE;
108         msg->r.SearchRequest.deref = LDAP_DEREFERENCE_NEVER;
109         msg->r.SearchRequest.timelimit = 0;
110         msg->r.SearchRequest.sizelimit = 0;
111         msg->r.SearchRequest.attributesonly = false;
112         msg->r.SearchRequest.tree = ldb_parse_tree(msg, "(objectclass=*)");
113         msg->r.SearchRequest.num_attributes = 0;
114         msg->r.SearchRequest.attributes = NULL;
115
116         req = ldap_request_send(conn, msg);
117         if (req == NULL) {
118                 printf("Could not setup ldap search\n");
119                 return false;
120         }
121
122         status = ldap_result_one(req, &result, LDAP_TAG_SearchResultEntry);
123         if (!NT_STATUS_IS_OK(status)) {
124                 printf("search failed - %s\n", nt_errstr(status));
125                 return false;
126         }
127
128         printf("received %d replies\n", req->num_replies);
129
130         r = &result->r.SearchResultEntry;
131                 
132         DEBUG(1,("\tdn: %s\n", r->dn));
133         for (i=0; i<r->num_attributes; i++) {
134                 int j;
135                 for (j=0; j<r->attributes[i].num_values; j++) {
136                         DEBUG(1,("\t%s: %d %.*s\n", r->attributes[i].name,
137                                  (int)r->attributes[i].values[j].length,
138                                  (int)r->attributes[i].values[j].length,
139                                  (char *)r->attributes[i].values[j].data));
140                         if (!(*basedn) && 
141                             strcasecmp("defaultNamingContext",r->attributes[i].name)==0) {
142                                 *basedn = talloc_asprintf(conn, "%.*s",
143                                                           (int)r->attributes[i].values[j].length,
144                                                           (char *)r->attributes[i].values[j].data);
145                         }
146                         if ((partitions != NULL) &&
147                             (strcasecmp("namingContexts", r->attributes[i].name) == 0)) {
148                                 char *entry = talloc_asprintf(conn, "%.*s",
149                                                               (int)r->attributes[i].values[j].length,
150                                                               (char *)r->attributes[i].values[j].data);
151                                 *partitions = str_list_add(*partitions, entry);
152                         }
153                 }
154         }
155
156         return ret;
157 }
158
159 static bool test_search_rootDSE_empty_substring(struct ldap_connection *conn)
160 {
161         bool ret = true;
162         struct ldap_message *msg, *result;
163         struct ldap_request *req;
164         NTSTATUS status;
165
166         printf("Testing RootDSE Search with objectclass= substring filter\n");
167
168         msg = new_ldap_message(conn);
169         if (!msg) {
170                 return false;
171         }
172
173         msg->type = LDAP_TAG_SearchRequest;
174         msg->r.SearchRequest.basedn = "";
175         msg->r.SearchRequest.scope = LDAP_SEARCH_SCOPE_BASE;
176         msg->r.SearchRequest.deref = LDAP_DEREFERENCE_NEVER;
177         msg->r.SearchRequest.timelimit = 0;
178         msg->r.SearchRequest.sizelimit = 0;
179         msg->r.SearchRequest.attributesonly = false;
180         msg->r.SearchRequest.tree = ldb_parse_tree(msg, "(objectclass=*)");
181         msg->r.SearchRequest.tree->operation = LDB_OP_SUBSTRING;
182         msg->r.SearchRequest.tree->u.substring.attr = "objectclass";
183         msg->r.SearchRequest.tree->u.substring.start_with_wildcard = 1;
184         msg->r.SearchRequest.tree->u.substring.end_with_wildcard = 1;
185         msg->r.SearchRequest.tree->u.substring.chunks = NULL;
186         msg->r.SearchRequest.num_attributes = 0;
187         msg->r.SearchRequest.attributes = NULL;
188
189         req = ldap_request_send(conn, msg);
190         if (req == NULL) {
191                 printf("Could not setup ldap search\n");
192                 return false;
193         }
194
195         status = ldap_result_one(req, &result, LDAP_TAG_SearchResultEntry);
196         if (!NT_STATUS_IS_OK(status)) {
197                 printf("looking for search result reply failed - %s\n", nt_errstr(status));
198                 return false;
199         }
200
201         printf("received %d replies\n", req->num_replies);
202
203         return ret;
204 }
205
206 static bool test_search_auth_empty_substring(struct ldap_connection *conn, const char *basedn)
207 {
208         bool ret = true;
209         struct ldap_message *msg, *result;
210         struct ldap_request *req;
211         NTSTATUS status;
212         struct ldap_Result *r;
213
214         printf("Testing authenticated base Search with objectclass= substring filter\n");
215
216         msg = new_ldap_message(conn);
217         if (!msg) {
218                 return false;
219         }
220
221         msg->type = LDAP_TAG_SearchRequest;
222         msg->r.SearchRequest.basedn = basedn;
223         msg->r.SearchRequest.scope = LDAP_SEARCH_SCOPE_BASE;
224         msg->r.SearchRequest.deref = LDAP_DEREFERENCE_NEVER;
225         msg->r.SearchRequest.timelimit = 0;
226         msg->r.SearchRequest.sizelimit = 0;
227         msg->r.SearchRequest.attributesonly = false;
228         msg->r.SearchRequest.tree = ldb_parse_tree(msg, "(objectclass=*)");
229         msg->r.SearchRequest.tree->operation = LDB_OP_SUBSTRING;
230         msg->r.SearchRequest.tree->u.substring.attr = "objectclass";
231         msg->r.SearchRequest.tree->u.substring.start_with_wildcard = 1;
232         msg->r.SearchRequest.tree->u.substring.end_with_wildcard = 1;
233         msg->r.SearchRequest.tree->u.substring.chunks = NULL;
234         msg->r.SearchRequest.num_attributes = 0;
235         msg->r.SearchRequest.attributes = NULL;
236
237         req = ldap_request_send(conn, msg);
238         if (req == NULL) {
239                 printf("Could not setup ldap search\n");
240                 return false;
241         }
242
243         status = ldap_result_one(req, &result, LDAP_TAG_SearchResultDone);
244         if (!NT_STATUS_IS_OK(status)) {
245                 printf("looking for search result done failed - %s\n", nt_errstr(status));
246                 return false;
247         }
248
249         printf("received %d replies\n", req->num_replies);
250
251         r = &result->r.SearchResultDone;
252
253         if (r->resultcode != LDAP_SUCCESS) {
254                 printf("search result done gave error - %s\n", ldb_strerror(r->resultcode));
255                 return false;
256         }
257
258         return ret;
259 }
260
261 static bool test_compare_sasl(struct ldap_connection *conn, const char *basedn)
262 {
263         struct ldap_message *msg, *rep;
264         struct ldap_request *req;
265         const char *val;
266         NTSTATUS status;
267
268         printf("Testing SASL Compare: %s\n", basedn);
269
270         if (!basedn) {
271                 return false;
272         }
273
274         msg = new_ldap_message(conn);
275         if (!msg) {
276                 return false;
277         }
278
279         msg->type = LDAP_TAG_CompareRequest;
280         msg->r.CompareRequest.dn = basedn;
281         msg->r.CompareRequest.attribute = talloc_strdup(msg, "objectClass");
282         val = "domain";
283         msg->r.CompareRequest.value = data_blob_talloc(msg, val, strlen(val));
284
285         req = ldap_request_send(conn, msg);
286         if (!req) {
287                 return false;
288         }
289
290         status = ldap_result_one(req, &rep, LDAP_TAG_CompareResponse);
291         if (!NT_STATUS_IS_OK(status)) {
292                 printf("error in ldap compare request - %s\n", nt_errstr(status));
293                 return false;
294         }
295
296         DEBUG(5,("Code: %d DN: [%s] ERROR:[%s] REFERRAL:[%s]\n",
297                 rep->r.CompareResponse.resultcode,
298                 rep->r.CompareResponse.dn,
299                 rep->r.CompareResponse.errormessage,
300                 rep->r.CompareResponse.referral));
301
302         return true;
303 }
304
305 /*
306  * This takes an AD error message and splits it into the WERROR code
307  * (WERR_DS_GENERIC if none found) and the reason (remaining string).
308  */
309 static WERROR ad_error(const char *err_msg, char **reason)
310 {
311         WERROR err = W_ERROR(strtol(err_msg, reason, 16));
312
313         if ((reason != NULL) && (*reason[0] != ':')) {
314                 return WERR_DS_GENERIC_ERROR; /* not an AD std error message */
315         }
316                 
317         if (reason != NULL) {
318                 *reason += 2; /* skip ": " */
319         }
320         return err;
321 }
322
323 /* This has to be done using the LDAP API since the LDB API does only transmit
324  * the error code and not the error message. */
325 static bool test_error_codes(struct torture_context *tctx,
326         struct ldap_connection *conn, const char *basedn)
327 {
328         struct ldap_message *msg, *rep;
329         struct ldap_request *req;
330         const char *err_code_str;
331         char *endptr;
332         WERROR err;
333         NTSTATUS status;
334
335         printf("Testing the most important error code -> error message conversions!\n");
336
337         if (!basedn) {
338                 return false;
339         }
340
341         msg = new_ldap_message(conn);
342         if (!msg) {
343                 return false;
344         }
345
346         printf(" Try a wrong addition\n");
347
348         msg->type = LDAP_TAG_AddRequest;
349         msg->r.AddRequest.dn = basedn;
350         msg->r.AddRequest.num_attributes = 0;
351         msg->r.AddRequest.attributes = NULL;
352
353         req = ldap_request_send(conn, msg);
354         if (!req) {
355                 return false;
356         }
357
358         status = ldap_result_one(req, &rep, LDAP_TAG_AddResponse);
359         if (!NT_STATUS_IS_OK(status)) {
360                 printf("error in ldap add request - %s\n", nt_errstr(status));
361                 return false;
362         }
363
364         if ((rep->r.AddResponse.resultcode == 0)
365                 || (rep->r.AddResponse.errormessage == NULL)
366                 || (strtol(rep->r.AddResponse.errormessage, &endptr,16) <= 0)
367                 || (*endptr != ':')) {
368                 printf("Invalid error message!\n");
369                 return false;
370         }
371
372         err = ad_error(rep->r.AddResponse.errormessage, &endptr);
373         err_code_str = win_errstr(err);
374         printf(" - Errorcode: %s; Reason: %s\n", err_code_str, endptr);
375         if ((!W_ERROR_EQUAL(err, WERR_DS_REFERRAL))
376                         || (rep->r.AddResponse.resultcode != LDAP_REFERRAL)) {
377                         return false;
378         }
379         if ((rep->r.AddResponse.referral == NULL)
380                         || (strstr(rep->r.AddResponse.referral, basedn) == NULL)) {
381                         return false;
382         }
383
384         printf(" Try another wrong addition\n");
385
386         msg->type = LDAP_TAG_AddRequest;
387         msg->r.AddRequest.dn = "";
388         msg->r.AddRequest.num_attributes = 0;
389         msg->r.AddRequest.attributes = NULL;
390
391         req = ldap_request_send(conn, msg);
392         if (!req) {
393                 return false;
394         }
395
396         status = ldap_result_one(req, &rep, LDAP_TAG_AddResponse);
397         if (!NT_STATUS_IS_OK(status)) {
398                 printf("error in ldap add request - %s\n", nt_errstr(status));
399                 return false;
400         }
401
402         if ((rep->r.AddResponse.resultcode == 0)
403                 || (rep->r.AddResponse.errormessage == NULL)
404                 || (strtol(rep->r.AddResponse.errormessage, &endptr,16) <= 0)
405                 || (*endptr != ':')) {
406                 printf("Invalid error message!\n");
407                 return false;
408         }
409
410         err = ad_error(rep->r.AddResponse.errormessage, &endptr);
411         err_code_str = win_errstr(err);
412         printf(" - Errorcode: %s; Reason: %s\n", err_code_str, endptr);
413         if ((!W_ERROR_EQUAL(err, WERR_DS_ROOT_MUST_BE_NC) &&
414              !W_ERROR_EQUAL(err, WERR_DS_NAMING_VIOLATION))
415                 || (rep->r.AddResponse.resultcode != LDAP_NAMING_VIOLATION)) {
416                 return false;
417         }
418
419         printf(" Try a wrong modification\n");
420
421         msg->type = LDAP_TAG_ModifyRequest;
422         msg->r.ModifyRequest.dn = basedn;
423         msg->r.ModifyRequest.num_mods = 0;
424         msg->r.ModifyRequest.mods = NULL;
425
426         req = ldap_request_send(conn, msg);
427         if (!req) {
428                 return false;
429         }
430
431         status = ldap_result_one(req, &rep, LDAP_TAG_ModifyResponse);
432         if (!NT_STATUS_IS_OK(status)) {
433                 printf("error in ldap modifification request - %s\n", nt_errstr(status));
434                 return false;
435         }
436
437         if ((rep->r.ModifyResponse.resultcode == 0)
438                 || (rep->r.ModifyResponse.errormessage == NULL)
439                 || (strtol(rep->r.ModifyResponse.errormessage, &endptr,16) <= 0)
440                 || (*endptr != ':')) {
441                 printf("Invalid error message!\n");
442                 return false;
443         }
444
445         err = ad_error(rep->r.ModifyResponse.errormessage, &endptr);
446         err_code_str = win_errstr(err);
447         printf(" - Errorcode: %s; Reason: %s\n", err_code_str, endptr);
448         if ((!W_ERROR_EQUAL(err, WERR_INVALID_PARAMETER) &&
449              !W_ERROR_EQUAL(err, WERR_DS_UNWILLING_TO_PERFORM))
450                 || (rep->r.ModifyResponse.resultcode != LDAP_UNWILLING_TO_PERFORM)) {
451                 return false;
452         }
453
454         printf(" Try another wrong modification\n");
455
456         msg->type = LDAP_TAG_ModifyRequest;
457         msg->r.ModifyRequest.dn = "";
458         msg->r.ModifyRequest.num_mods = 0;
459         msg->r.ModifyRequest.mods = NULL;
460
461         req = ldap_request_send(conn, msg);
462         if (!req) {
463                 return false;
464         }
465
466         status = ldap_result_one(req, &rep, LDAP_TAG_ModifyResponse);
467         if (!NT_STATUS_IS_OK(status)) {
468                 printf("error in ldap modifification request - %s\n", nt_errstr(status));
469                 return false;
470         }
471
472         if ((rep->r.ModifyResponse.resultcode == 0)
473                 || (rep->r.ModifyResponse.errormessage == NULL)
474                 || (strtol(rep->r.ModifyResponse.errormessage, &endptr,16) <= 0)
475                 || (*endptr != ':')) {
476                 printf("Invalid error message!\n");
477                 return false;
478         }
479
480         err = ad_error(rep->r.ModifyResponse.errormessage, &endptr);
481         err_code_str = win_errstr(err);
482         printf(" - Errorcode: %s; Reason: %s\n", err_code_str, endptr);
483         if ((!W_ERROR_EQUAL(err, WERR_INVALID_PARAMETER) &&
484              !W_ERROR_EQUAL(err, WERR_DS_UNWILLING_TO_PERFORM))
485                 || (rep->r.ModifyResponse.resultcode != LDAP_UNWILLING_TO_PERFORM)) {
486                 return false;
487         }
488
489         printf(" Try a wrong removal\n");
490
491         msg->type = LDAP_TAG_DelRequest;
492         msg->r.DelRequest.dn = basedn;
493
494         req = ldap_request_send(conn, msg);
495         if (!req) {
496                 return false;
497         }
498
499         status = ldap_result_one(req, &rep, LDAP_TAG_DelResponse);
500         if (!NT_STATUS_IS_OK(status)) {
501                 printf("error in ldap removal request - %s\n", nt_errstr(status));
502                 return false;
503         }
504
505         if ((rep->r.DelResponse.resultcode == 0)
506                 || (rep->r.DelResponse.errormessage == NULL)
507                 || (strtol(rep->r.DelResponse.errormessage, &endptr,16) <= 0)
508                 || (*endptr != ':')) {
509                 printf("Invalid error message!\n");
510                 return false;
511         }
512
513         err = ad_error(rep->r.DelResponse.errormessage, &endptr);
514         err_code_str = win_errstr(err);
515         printf(" - Errorcode: %s; Reason: %s\n", err_code_str, endptr);
516         if ((!W_ERROR_EQUAL(err, WERR_DS_CANT_DELETE) &&
517              !W_ERROR_EQUAL(err, WERR_DS_UNWILLING_TO_PERFORM))
518                 || (rep->r.DelResponse.resultcode != LDAP_UNWILLING_TO_PERFORM)) {
519                 return false;
520         }
521
522         printf(" Try another wrong removal\n");
523
524         msg->type = LDAP_TAG_DelRequest;
525         msg->r.DelRequest.dn = "";
526
527         req = ldap_request_send(conn, msg);
528         if (!req) {
529                 return false;
530         }
531
532         status = ldap_result_one(req, &rep, LDAP_TAG_DelResponse);
533         if (!NT_STATUS_IS_OK(status)) {
534                 printf("error in ldap removal request - %s\n", nt_errstr(status));
535                 return false;
536         }
537
538         if ((rep->r.DelResponse.resultcode == 0)
539                 || (rep->r.DelResponse.errormessage == NULL)
540                 || (strtol(rep->r.DelResponse.errormessage, &endptr,16) <= 0)
541                 || (*endptr != ':')) {
542                 printf("Invalid error message!\n");
543                 return false;
544         }
545         
546         err = ad_error(rep->r.DelResponse.errormessage, &endptr);
547         err_code_str = win_errstr(err);
548         printf(" - Errorcode: %s; Reason: %s\n", err_code_str, endptr);
549         if ((!W_ERROR_EQUAL(err, WERR_DS_OBJ_NOT_FOUND) &&
550              !W_ERROR_EQUAL(err, WERR_DS_NO_SUCH_OBJECT))
551                 || (rep->r.DelResponse.resultcode != LDAP_NO_SUCH_OBJECT)) {
552                 return false;
553         }
554
555         printf(" Try a wrong rename\n");
556
557         msg->type = LDAP_TAG_ModifyDNRequest;
558         msg->r.ModifyDNRequest.dn = basedn;
559         msg->r.ModifyDNRequest.newrdn = "dc=test";
560         msg->r.ModifyDNRequest.deleteolddn = true;
561         msg->r.ModifyDNRequest.newsuperior = NULL;
562
563         req = ldap_request_send(conn, msg);
564         if (!req) {
565                 return false;
566         }
567
568         status = ldap_result_one(req, &rep, LDAP_TAG_ModifyDNResponse);
569         if (!NT_STATUS_IS_OK(status)) {
570                 printf("error in ldap rename request - %s\n", nt_errstr(status));
571                 return false;
572         }
573
574         if ((rep->r.ModifyDNResponse.resultcode == 0)
575                 || (rep->r.ModifyDNResponse.errormessage == NULL)
576                 || (strtol(rep->r.ModifyDNResponse.errormessage, &endptr,16) <= 0)
577                 || (*endptr != ':')) {
578                 printf("Invalid error message!\n");
579                 return false;
580         }
581
582         err = ad_error(rep->r.ModifyDNResponse.errormessage, &endptr);
583         err_code_str = win_errstr(err);
584         printf(" - Errorcode: %s; Reason: %s\n", err_code_str, endptr);
585         if ((!W_ERROR_EQUAL(err, WERR_DS_NO_PARENT_OBJECT) &&
586              !W_ERROR_EQUAL(err, WERR_DS_GENERIC_ERROR))
587                 || (rep->r.ModifyDNResponse.resultcode != LDAP_OTHER)) {
588                 return false;
589         }
590
591         printf(" Try another wrong rename\n");
592
593         msg->type = LDAP_TAG_ModifyDNRequest;
594         msg->r.ModifyDNRequest.dn = basedn;
595         msg->r.ModifyDNRequest.newrdn = basedn;
596         msg->r.ModifyDNRequest.deleteolddn = true;
597         msg->r.ModifyDNRequest.newsuperior = NULL;
598
599         req = ldap_request_send(conn, msg);
600         if (!req) {
601                 return false;
602         }
603
604         status = ldap_result_one(req, &rep, LDAP_TAG_ModifyDNResponse);
605         if (!NT_STATUS_IS_OK(status)) {
606                 printf("error in ldap rename request - %s\n", nt_errstr(status));
607                 return false;
608         }
609
610         if ((rep->r.ModifyDNResponse.resultcode == 0)
611                 || (rep->r.ModifyDNResponse.errormessage == NULL)
612                 || (strtol(rep->r.ModifyDNResponse.errormessage, &endptr,16) <= 0)
613                 || (*endptr != ':')) {
614                 printf("Invalid error message!\n");
615                 return false;
616         }
617
618         err = ad_error(rep->r.ModifyDNResponse.errormessage, &endptr);
619         err_code_str = win_errstr(err);
620         printf(" - Errorcode: %s; Reason: %s\n", err_code_str, endptr);
621         if ((!W_ERROR_EQUAL(err, WERR_INVALID_PARAMETER) &&
622              !W_ERROR_EQUAL(err, WERR_DS_NAMING_VIOLATION))
623                 || (rep->r.ModifyDNResponse.resultcode != LDAP_NAMING_VIOLATION)) {
624                 return false;
625         }
626
627         printf(" Try another wrong rename\n");
628
629         msg->type = LDAP_TAG_ModifyDNRequest;
630         msg->r.ModifyDNRequest.dn = basedn;
631         msg->r.ModifyDNRequest.newrdn = "";
632         msg->r.ModifyDNRequest.deleteolddn = true;
633         msg->r.ModifyDNRequest.newsuperior = NULL;
634
635         req = ldap_request_send(conn, msg);
636         if (!req) {
637                 return false;
638         }
639
640         status = ldap_result_one(req, &rep, LDAP_TAG_ModifyDNResponse);
641         if (!NT_STATUS_IS_OK(status)) {
642                 printf("error in ldap rename request - %s\n", nt_errstr(status));
643                 return false;
644         }
645
646         if ((rep->r.ModifyDNResponse.resultcode == 0)
647                 || (rep->r.ModifyDNResponse.errormessage == NULL)
648                 || (strtol(rep->r.ModifyDNResponse.errormessage, &endptr,16) <= 0)
649                 || (*endptr != ':')) {
650                 printf("Invalid error message!\n");
651                 return false;
652         }
653
654         err = ad_error(rep->r.ModifyDNResponse.errormessage, &endptr);
655         err_code_str = win_errstr(err);
656         printf(" - Errorcode: %s; Reason: %s\n", err_code_str, endptr);
657         if ((!W_ERROR_EQUAL(err, WERR_INVALID_PARAMETER) &&
658              !W_ERROR_EQUAL(err, WERR_DS_PROTOCOL_ERROR))
659                 || (rep->r.ModifyDNResponse.resultcode != LDAP_PROTOCOL_ERROR)) {
660                 return false;
661         }
662
663         printf(" Try another wrong rename\n");
664
665         msg->type = LDAP_TAG_ModifyDNRequest;
666         msg->r.ModifyDNRequest.dn = "";
667         msg->r.ModifyDNRequest.newrdn = "cn=temp";
668         msg->r.ModifyDNRequest.deleteolddn = true;
669         msg->r.ModifyDNRequest.newsuperior = NULL;
670
671         req = ldap_request_send(conn, msg);
672         if (!req) {
673                 return false;
674         }
675
676         status = ldap_result_one(req, &rep, LDAP_TAG_ModifyDNResponse);
677         if (!NT_STATUS_IS_OK(status)) {
678                 printf("error in ldap rename request - %s\n", nt_errstr(status));
679                 return false;
680         }
681
682         if ((rep->r.ModifyDNResponse.resultcode == 0)
683                 || (rep->r.ModifyDNResponse.errormessage == NULL)
684                 || (strtol(rep->r.ModifyDNResponse.errormessage, &endptr,16) <= 0)
685                 || (*endptr != ':')) {
686                 printf("Invalid error message!\n");
687                 return false;
688         }
689
690         err = ad_error(rep->r.ModifyDNResponse.errormessage, &endptr);
691         err_code_str = win_errstr(err);
692         printf(" - Errorcode: %s; Reason: %s\n", err_code_str, endptr);
693         if ((!W_ERROR_EQUAL(err, WERR_DS_OBJ_NOT_FOUND) &&
694              !W_ERROR_EQUAL(err, WERR_DS_NO_SUCH_OBJECT))
695                 || (rep->r.ModifyDNResponse.resultcode != LDAP_NO_SUCH_OBJECT)) {
696                 return false;
697         }
698
699         return true;
700 }
701
702 static bool test_referrals(struct torture_context *tctx, TALLOC_CTX *mem_ctx,
703         const char *url, const char *basedn, const char **partitions)
704 {
705         struct ldb_context *ldb;
706         struct ldb_result *res;
707         const char * const *attrs = { NULL };
708         struct ldb_dn *dn1, *dn2;
709         int ret;
710         int i, j, k;
711         char *tempstr;
712         bool found, l_found;
713
714         printf("Testing referrals\n");
715
716         if (partitions[0] == NULL) {
717                 printf("Partitions list empty!\n");
718                 return false;
719         }
720
721         if (strcmp(partitions[0], basedn) != 0) {
722                 printf("The first (root) partition DN should be the base DN!\n");
723                 return false;
724         }
725
726         ldb = ldb_wrap_connect(mem_ctx, tctx->ev, tctx->lp_ctx, url,
727                                NULL, popt_get_cmdline_credentials(), 0);
728
729         /* "partitions[i]" are the partitions for which we search the parents */
730         for (i = 1; partitions[i] != NULL; i++) {
731                 dn1 = ldb_dn_new(mem_ctx, ldb, partitions[i]);
732                 if (dn1 == NULL) {
733                         printf("Out of memory\n");
734                         talloc_free(ldb);
735                         return false;
736                 }
737
738                 /* search using base scope */
739                 /* "partitions[j]" are the parent candidates */
740                 for (j = str_list_length(partitions) - 1; j >= 0; --j) {
741                         dn2 = ldb_dn_new(mem_ctx, ldb, partitions[j]);
742                         if (dn2 == NULL) {
743                                 printf("Out of memory\n");
744                                 talloc_free(ldb);
745                                 return false;
746                         }
747
748                         ret = ldb_search(ldb, mem_ctx, &res, dn2,
749                                          LDB_SCOPE_BASE, attrs,
750                                          "(foo=bar)");
751                         if (ret != LDB_SUCCESS) {
752                                 printf("%s", ldb_errstring(ldb));
753                                 talloc_free(ldb);
754                                 return false;
755                         }
756
757                         if (res->refs != NULL) {
758                                 printf("There shouldn't be generated any referrals in the base scope!\n");
759                                 talloc_free(ldb);
760                                 return false;
761                         }
762
763                         talloc_free(res);
764                         talloc_free(dn2);
765                 }
766
767                 /* search using onelevel scope */
768                 found = false;
769                 /* "partitions[j]" are the parent candidates */
770                 for (j = str_list_length(partitions) - 1; j >= 0; --j) {
771                         dn2 = ldb_dn_new(mem_ctx, ldb, partitions[j]);
772                         if (dn2 == NULL) {
773                                 printf("Out of memory\n");
774                                 talloc_free(ldb);
775                                 return false;
776                         }
777
778                         ret = ldb_search(ldb, mem_ctx, &res, dn2,
779                                          LDB_SCOPE_ONELEVEL, attrs,
780                                          "(foo=bar)");
781                         if (ret != LDB_SUCCESS) {
782                                 printf("%s", ldb_errstring(ldb));
783                                 talloc_free(ldb);
784                                 return false;
785                         }
786
787                         tempstr = talloc_asprintf(mem_ctx, "/%s??base",
788                                                   partitions[i]);
789                         if (tempstr == NULL) {
790                                 printf("Out of memory\n");
791                                 talloc_free(ldb);
792                                 return false;
793                         }
794
795                         /* Try to find or find not a matching referral */
796                         l_found = false;
797                         for (k = 0; (!l_found) && (res->refs != NULL)
798                             && (res->refs[k] != NULL); k++) {
799                                 if (strstr(res->refs[k], tempstr) != NULL) {
800                                         l_found = true;
801                                 }
802                         }
803
804                         talloc_free(tempstr);
805
806                         if ((!found) && (ldb_dn_compare_base(dn2, dn1) == 0)
807                             && (ldb_dn_compare(dn2, dn1) != 0)) {
808                                 /* This is a referral candidate */
809                                 if (!l_found) {
810                                         printf("A required referral hasn't been found on onelevel scope (%s -> %s)!\n", partitions[j], partitions[i]);
811                                         talloc_free(ldb);
812                                         return false;
813                                 }
814                                 found = true;
815                         } else {
816                                 /* This isn't a referral candidate */
817                                 if (l_found) {
818                                         printf("A unrequired referral has been found on onelevel scope (%s -> %s)!\n", partitions[j], partitions[i]);
819                                         talloc_free(ldb);
820                                         return false;
821                                 }
822                         }
823
824                         talloc_free(res);
825                         talloc_free(dn2);
826                 }
827
828                 /* search using subtree scope */
829                 found = false;
830                 /* "partitions[j]" are the parent candidates */
831                 for (j = str_list_length(partitions) - 1; j >= 0; --j) {
832                         dn2 = ldb_dn_new(mem_ctx, ldb, partitions[j]);
833                         if (dn2 == NULL) {
834                                 printf("Out of memory\n");
835                                 talloc_free(ldb);
836                                 return false;
837                         }
838
839                         ret = ldb_search(ldb, mem_ctx, &res, dn2,
840                                          LDB_SCOPE_SUBTREE, attrs,
841                                          "(foo=bar)");
842                         if (ret != LDB_SUCCESS) {
843                                 printf("%s", ldb_errstring(ldb));
844                                 talloc_free(ldb);
845                                 return false;
846                         }
847
848                         tempstr = talloc_asprintf(mem_ctx, "/%s",
849                                                   partitions[i]);
850                         if (tempstr == NULL) {
851                                 printf("Out of memory\n");
852                                 talloc_free(ldb);
853                                 return false;
854                         }
855
856                         /* Try to find or find not a matching referral */
857                         l_found = false;
858                         for (k = 0; (!l_found) && (res->refs != NULL)
859                             && (res->refs[k] != NULL); k++) {
860                                 if (strstr(res->refs[k], tempstr) != NULL) {
861                                         l_found = true;
862                                 }
863                         }
864
865                         talloc_free(tempstr);
866
867                         if ((!found) && (ldb_dn_compare_base(dn2, dn1) == 0)
868                             && (ldb_dn_compare(dn2, dn1) != 0)) {
869                                 /* This is a referral candidate */
870                                 if (!l_found) {
871                                         printf("A required referral hasn't been found on subtree scope (%s -> %s)!\n", partitions[j], partitions[i]);
872                                         talloc_free(ldb);
873                                         return false;
874                                 }
875                                 found = true;
876                         } else {
877                                 /* This isn't a referral candidate */
878                                 if (l_found) {
879                                         printf("A unrequired referral has been found on subtree scope (%s -> %s)!\n", partitions[j], partitions[i]);
880                                         talloc_free(ldb);
881                                         return false;
882                                 }
883                         }
884
885                         talloc_free(res);
886                         talloc_free(dn2);
887                 }
888
889                 talloc_free(dn1);
890         }
891
892         talloc_free(ldb);
893
894         return true;
895 }
896
897 static bool test_abandon_request(struct torture_context *tctx,
898         struct ldap_connection *conn, const char *basedn)
899 {
900         struct ldap_message *msg;
901         struct ldap_request *req;
902         NTSTATUS status;
903
904         printf("Testing the AbandonRequest with an old message id!\n");
905
906         if (!basedn) {
907                 return false;
908         }
909
910         msg = new_ldap_message(conn);
911         if (!msg) {
912                 return false;
913         }
914
915         printf(" Try a AbandonRequest for an old message id\n");
916
917         msg->type = LDAP_TAG_AbandonRequest;
918         msg->r.AbandonRequest.messageid = 1;
919
920         req = ldap_request_send(conn, msg);
921         if (!req) {
922                 return false;
923         }
924
925         status = ldap_request_wait(req);
926         if (!NT_STATUS_IS_OK(status)) {
927                 printf("error in ldap abandon request - %s\n", nt_errstr(status));
928                 return false;
929         }
930
931         return true;
932 }
933
934
935 bool torture_ldap_basic(struct torture_context *torture)
936 {
937         NTSTATUS status;
938         struct ldap_connection *conn;
939         TALLOC_CTX *mem_ctx;
940         bool ret = true;
941         const char *host = torture_setting_string(torture, "host", NULL);
942         const char *userdn = torture_setting_string(torture, "ldap_userdn", NULL);
943         const char *secret = torture_setting_string(torture, "ldap_secret", NULL);
944         const char *url;
945         const char *basedn;
946         const char **partitions;
947
948         mem_ctx = talloc_init("torture_ldap_basic");
949
950         url = talloc_asprintf(mem_ctx, "ldap://%s/", host);
951
952         status = torture_ldap_connection(torture, &conn, url);
953         if (!NT_STATUS_IS_OK(status)) {
954                 return false;
955         }
956
957         if (!test_search_rootDSE(conn, &basedn, &partitions)) {
958                 ret = false;
959         }
960
961         if (!test_search_rootDSE_empty_substring(conn)) {
962                 ret = false;
963         }
964
965         /* other bind tests here */
966
967         if (!test_multibind(conn, userdn, secret)) {
968                 ret = false;
969         }
970
971         if (!test_bind_sasl(torture, conn, popt_get_cmdline_credentials())) {
972                 ret = false;
973         }
974
975         if (!test_search_auth_empty_substring(conn, basedn)) {
976                 ret = false;
977         }
978
979         if (!test_compare_sasl(conn, basedn)) {
980                 ret = false;
981         }
982
983         /* error codes test here */
984
985         if (!test_error_codes(torture, conn, basedn)) {
986                 ret = false;
987         }
988
989         /* referrals test here */
990
991         if (!test_referrals(torture, mem_ctx, url, basedn, partitions)) {
992                 ret = false;
993         }
994
995         if (!test_abandon_request(torture, conn, basedn)) {
996                 ret = false;
997         }
998
999         /* if there are no more tests we are closing */
1000         torture_ldap_close(conn);
1001         talloc_free(mem_ctx);
1002
1003         return ret;
1004 }
1005