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