r15788: Do not crash when no result is returned
[sfrench/samba-autobuild/.git] / source4 / torture / ldap / cldap.c
1 /* 
2    Unix SMB/CIFS mplementation.
3
4    test CLDAP operations
5    
6    Copyright (C) Andrew Tridgell 2005
7     
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21    
22 */
23
24 #include "includes.h"
25 #include "libcli/cldap/cldap.h"
26 #include "libcli/ldap/ldap.h"
27 #include "librpc/gen_ndr/ndr_nbt.h"
28 #include "torture/torture.h"
29 #include "lib/ldb/include/ldb.h"
30
31 #define CHECK_STATUS(status, correct) do { \
32         if (!NT_STATUS_EQUAL(status, correct)) { \
33                 printf("(%s) Incorrect status %s - should be %s\n", \
34                        __location__, nt_errstr(status), nt_errstr(correct)); \
35                 ret = False; \
36                 goto done; \
37         } \
38 } while (0)
39
40 /*
41   test netlogon operations
42 */
43 static BOOL test_cldap_netlogon(TALLOC_CTX *mem_ctx, const char *dest)
44 {
45         struct cldap_socket *cldap = cldap_socket_init(mem_ctx, NULL);
46         NTSTATUS status;
47         struct cldap_netlogon search, empty_search;
48         union nbt_cldap_netlogon n1;
49         struct GUID guid;
50         int i;
51         BOOL ret = True;
52
53         ZERO_STRUCT(search);
54         search.in.dest_address = dest;
55         search.in.acct_control = -1;
56         search.in.version = 6;
57
58         empty_search = search;
59
60         printf("Trying without any attributes\n");
61         search = empty_search;
62         status = cldap_netlogon(cldap, mem_ctx, &search);
63         CHECK_STATUS(status, NT_STATUS_OK);
64
65         n1 = search.out.netlogon;
66
67         search.in.user         = "Administrator";
68         search.in.realm        = n1.logon5.dns_domain;
69         search.in.host         = "__cldap_torture__";
70
71         printf("Scanning for netlogon levels\n");
72         for (i=0;i<256;i++) {
73                 search.in.version = i;
74                 printf("Trying netlogon level %d\n", i);
75                 status = cldap_netlogon(cldap, mem_ctx, &search);
76                 CHECK_STATUS(status, NT_STATUS_OK);
77         }
78
79         printf("Scanning for netlogon level bits\n");
80         for (i=0;i<31;i++) {
81                 search.in.version = (1<<i);
82                 printf("Trying netlogon level 0x%x\n", i);
83                 status = cldap_netlogon(cldap, mem_ctx, &search);
84                 CHECK_STATUS(status, NT_STATUS_OK);
85         }
86
87         search.in.version = 6;
88         status = cldap_netlogon(cldap, mem_ctx, &search);
89         CHECK_STATUS(status, NT_STATUS_OK);
90
91         printf("Trying with User=NULL\n");
92
93         search.in.user = NULL;
94         status = cldap_netlogon(cldap, mem_ctx, &search);
95         CHECK_STATUS(status, NT_STATUS_OK);
96
97         printf("Trying with User=Administrator\n");
98
99         search.in.user = "Administrator";
100         status = cldap_netlogon(cldap, mem_ctx, &search);
101         CHECK_STATUS(status, NT_STATUS_OK);
102
103         printf("Trying with a GUID\n");
104         search.in.realm       = NULL;
105         search.in.domain_guid = GUID_string(mem_ctx, &n1.logon5.domain_uuid);
106         status = cldap_netlogon(cldap, mem_ctx, &search);
107         CHECK_STATUS(status, NT_STATUS_OK);
108
109         printf("Trying with a incorrect GUID\n");
110         guid = GUID_random();
111         search.in.user        = NULL;
112         search.in.domain_guid = GUID_string(mem_ctx, &guid);
113         status = cldap_netlogon(cldap, mem_ctx, &search);
114         CHECK_STATUS(status, NT_STATUS_NOT_FOUND);
115
116         printf("Trying with a AAC\n");
117         search.in.acct_control = 0x180;
118         search.in.realm = n1.logon5.dns_domain;
119         status = cldap_netlogon(cldap, mem_ctx, &search);
120         CHECK_STATUS(status, NT_STATUS_OK);
121
122         printf("Trying with a bad AAC\n");
123         search.in.acct_control = 0xFF00FF00;
124         search.in.realm = n1.logon5.dns_domain;
125         status = cldap_netlogon(cldap, mem_ctx, &search);
126         CHECK_STATUS(status, NT_STATUS_OK);
127
128         printf("Trying with a user only\n");
129         search = empty_search;
130         search.in.user = "Administrator";
131         status = cldap_netlogon(cldap, mem_ctx, &search);
132         CHECK_STATUS(status, NT_STATUS_OK);
133
134         printf("Trying with just a bad username\n");
135         search.in.user = "___no_such_user___";
136         status = cldap_netlogon(cldap, mem_ctx, &search);
137         CHECK_STATUS(status, NT_STATUS_OK);
138
139         printf("Trying with just a bad domain\n");
140         search = empty_search;
141         search.in.realm = "___no_such_domain___";
142         status = cldap_netlogon(cldap, mem_ctx, &search);
143         CHECK_STATUS(status, NT_STATUS_NOT_FOUND);
144
145         printf("Trying with a incorrect domain and correct guid\n");
146         search.in.domain_guid = GUID_string(mem_ctx, &n1.logon5.domain_uuid);
147         status = cldap_netlogon(cldap, mem_ctx, &search);
148         CHECK_STATUS(status, NT_STATUS_OK);
149
150         printf("Trying with a incorrect domain and incorrect guid\n");
151         search.in.domain_guid = GUID_string(mem_ctx, &guid);
152         status = cldap_netlogon(cldap, mem_ctx, &search);
153         CHECK_STATUS(status, NT_STATUS_NOT_FOUND);
154
155         printf("Trying with a incorrect GUID and correct domain\n");
156         search.in.domain_guid = GUID_string(mem_ctx, &guid);
157         search.in.realm = n1.logon5.dns_domain;
158         status = cldap_netlogon(cldap, mem_ctx, &search);
159         CHECK_STATUS(status, NT_STATUS_OK);
160
161 done:
162         return ret;     
163 }
164
165 /*
166   convert a ldap result message to a ldb message. This allows us to
167   use the convenient ldif dump routines in ldb to print out cldap
168   search results
169 */
170 static struct ldb_message *ldap_msg_to_ldb(TALLOC_CTX *mem_ctx, struct ldap_SearchResEntry *res)
171 {
172         struct ldb_message *msg;
173
174         msg = ldb_msg_new(mem_ctx);
175         msg->dn = ldb_dn_explode_or_special(msg, res->dn);
176         msg->num_elements = res->num_attributes;
177         msg->elements = talloc_steal(msg, res->attributes);
178         return msg;
179 }
180
181 /*
182   dump a set of cldap results
183 */
184 static void cldap_dump_results(struct cldap_search *search)
185 {
186         struct ldb_ldif ldif;
187         struct ldb_context *ldb;
188
189         if (!search || !(search->out.response)) {
190                 return;
191         }
192
193         /* we need a ldb context to use ldb_ldif_write_file() */
194         ldb = ldb_init(NULL);
195
196         ZERO_STRUCT(ldif);
197         ldif.msg = ldap_msg_to_ldb(ldb, search->out.response);
198
199         ldb_ldif_write_file(ldb, stdout, &ldif);
200
201         talloc_free(ldb);
202 }
203
204 /*
205   test generic cldap operations
206 */
207 static BOOL test_cldap_generic(TALLOC_CTX *mem_ctx, const char *dest)
208 {
209         struct cldap_socket *cldap = cldap_socket_init(mem_ctx, NULL);
210         NTSTATUS status;
211         struct cldap_search search;
212         BOOL ret = True;
213         const char *attrs[] = { "currentTime", "highestCommittedUSN", NULL };
214
215         ZERO_STRUCT(search);
216         search.in.dest_address = dest;
217         search.in.timeout = 10;
218         search.in.retries = 3;
219
220         status = cldap_search(cldap, mem_ctx, &search);
221         CHECK_STATUS(status, NT_STATUS_OK);
222
223         printf("fetching whole rootDSE\n");
224         search.in.filter = "(objectclass=*)";
225         search.in.attributes = NULL;
226
227         status = cldap_search(cldap, mem_ctx, &search);
228         CHECK_STATUS(status, NT_STATUS_OK);
229
230         if (DEBUGLVL(3)) cldap_dump_results(&search);
231
232         printf("fetching currentTime and USN\n");
233         search.in.filter = "(objectclass=*)";
234         search.in.attributes = attrs;
235
236         status = cldap_search(cldap, mem_ctx, &search);
237         CHECK_STATUS(status, NT_STATUS_OK);
238         
239         if (DEBUGLVL(3)) cldap_dump_results(&search);
240
241         printf("Testing a false expression\n");
242         search.in.filter = "(&(objectclass=*)(highestCommittedUSN=2))";
243         search.in.attributes = attrs;
244
245         status = cldap_search(cldap, mem_ctx, &search);
246         CHECK_STATUS(status, NT_STATUS_OK);
247         
248         if (DEBUGLVL(3)) cldap_dump_results(&search);
249         
250
251 done:
252         return ret;     
253 }
254
255 BOOL torture_cldap(struct torture_context *torture)
256 {
257         TALLOC_CTX *mem_ctx;
258         BOOL ret = True;
259         const char *host = lp_parm_string(-1, "torture", "host");
260
261         mem_ctx = talloc_init("torture_cldap");
262
263         ret &= test_cldap_netlogon(mem_ctx, host);
264
265         /* at the moment don't consider this failing to be a failure */
266         test_cldap_generic(mem_ctx, host);
267
268         talloc_free(mem_ctx);
269
270         return ret;
271 }
272