s4-loadparm: 2nd half of lp_ to lpcfg_ conversion
[samba.git] / source4 / torture / ntp / ntp_signd.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Test NTP authentication support
5
6    Copyright (C) Andrew Bartlet <abartlet@samba.org> 2008
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 3 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, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "torture/smbtorture.h"
24 #include <tevent.h>
25 #include "lib/stream/packet.h"
26 #include "lib/tsocket/tsocket.h"
27 #include "libcli/util/tstream.h"
28 #include "torture/rpc/torture_rpc.h"
29 #include "../lib/crypto/crypto.h"
30 #include "libcli/auth/libcli_auth.h"
31 #include "librpc/gen_ndr/ndr_netlogon_c.h"
32 #include "librpc/gen_ndr/ndr_ntp_signd.h"
33 #include "param/param.h"
34 #include "system/network.h"
35
36 #define TEST_MACHINE_NAME "ntpsigndtest"
37
38 struct signd_client_state {
39         struct tsocket_address *local_address;
40         struct tsocket_address *remote_address;
41
42         struct tstream_context *tstream;
43         struct tevent_queue *send_queue;
44
45         uint8_t request_hdr[4];
46         struct iovec request_iov[2];
47
48         DATA_BLOB reply;
49
50         NTSTATUS status;
51 };
52
53 /*
54  * A torture test to show that the unix domain socket protocol is
55  * operating correctly, and the signatures are as expected
56  */
57 static bool test_ntp_signd(struct torture_context *tctx,
58                            struct dcerpc_pipe *p,
59                            struct cli_credentials *credentials)
60 {
61         struct netlogon_creds_CredentialState *creds;
62         TALLOC_CTX *mem_ctx = talloc_new(tctx);
63
64         struct netr_ServerReqChallenge r;
65         struct netr_ServerAuthenticate3 a;
66         struct netr_Credential credentials1, credentials2, credentials3;
67         uint32_t rid;
68         const char *machine_name;
69         const struct samr_Password *pwhash = cli_credentials_get_nt_hash(credentials, mem_ctx);
70         uint32_t negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
71
72         struct sign_request sign_req;
73         struct signed_reply signed_reply;
74         DATA_BLOB sign_req_blob;
75
76         struct signd_client_state *signd_client;
77         struct tevent_req *req;
78         char *unix_address;
79         int sys_errno;
80
81         struct MD5Context ctx;
82         uint8_t sig[16];
83         enum ndr_err_code ndr_err;
84         bool ok;
85         int rc;
86
87         machine_name = cli_credentials_get_workstation(credentials);
88
89         torture_comment(tctx, "Testing ServerReqChallenge\n");
90
91         r.in.server_name = NULL;
92         r.in.computer_name = machine_name;
93         r.in.credentials = &credentials1;
94         r.out.return_credentials = &credentials2;
95
96         generate_random_buffer(credentials1.data, sizeof(credentials1.data));
97
98         torture_assert_ntstatus_ok(tctx,
99                 dcerpc_netr_ServerReqChallenge_r(p->binding_handle, tctx, &r),
100                 "ServerReqChallenge failed");
101         torture_assert_ntstatus_ok(tctx, r.out.result,
102                 "ServerReqChallenge failed");
103
104         a.in.server_name = NULL;
105         a.in.account_name = talloc_asprintf(tctx, "%s$", machine_name);
106         a.in.secure_channel_type = SEC_CHAN_WKSTA;
107         a.in.computer_name = machine_name;
108         a.in.negotiate_flags = &negotiate_flags;
109         a.in.credentials = &credentials3;
110         a.out.return_credentials = &credentials3;
111         a.out.negotiate_flags = &negotiate_flags;
112         a.out.rid = &rid;
113
114         creds = netlogon_creds_client_init(tctx, a.in.account_name,
115                                            a.in.computer_name,
116                                            &credentials1, &credentials2, 
117                                            pwhash, &credentials3,
118                                            negotiate_flags);
119         
120         torture_assert(tctx, creds != NULL, "memory allocation");
121
122         torture_comment(tctx, "Testing ServerAuthenticate3\n");
123
124         torture_assert_ntstatus_ok(tctx,
125                 dcerpc_netr_ServerAuthenticate3_r(p->binding_handle, tctx, &a),
126                 "ServerAuthenticate3 failed");
127         torture_assert_ntstatus_ok(tctx, a.out.result,
128                 "ServerAuthenticate3 failed");
129         torture_assert(tctx,
130                        netlogon_creds_client_check(creds, &credentials3),
131                        "Credential chaining failed");
132
133         sign_req.op = SIGN_TO_CLIENT;
134         sign_req.packet_id = 1;
135         sign_req.key_id = rid;
136         sign_req.packet_to_sign = data_blob_string_const("I am a tea pot");
137         
138         ndr_err = ndr_push_struct_blob(&sign_req_blob,
139                                        mem_ctx,
140                                        &sign_req,
141                                        (ndr_push_flags_fn_t)ndr_push_sign_request);
142         torture_assert(tctx,
143                        NDR_ERR_CODE_IS_SUCCESS(ndr_err),
144                        "Failed to push sign_req");
145
146         signd_client = talloc(mem_ctx, struct signd_client_state);
147
148         /* Create socket addresses */
149         torture_comment(tctx, "Creating the socket addresses\n");
150         rc = tsocket_address_unix_from_path(signd_client, "",
151                                        &signd_client->local_address);
152         torture_assert(tctx, rc == 0,
153                        "Failed to create local address from unix path.");
154
155         unix_address = talloc_asprintf(signd_client,
156                                         "%s/socket",
157                                         lpcfg_ntp_signd_socket_directory(tctx->lp_ctx));
158         rc = tsocket_address_unix_from_path(mem_ctx,
159                                             unix_address,
160                                             &signd_client->remote_address);
161         torture_assert(tctx, rc == 0,
162                        "Failed to create remote address from unix path.");
163
164         /* Connect to the unix socket */
165         torture_comment(tctx, "Connecting to the unix socket\n");
166         req = tstream_unix_connect_send(signd_client,
167                                         tctx->ev,
168                                         signd_client->local_address,
169                                         signd_client->remote_address);
170         torture_assert(tctx, req != NULL,
171                        "Failed to create a tstream unix connect request.");
172
173         ok = tevent_req_poll(req, tctx->ev);
174         torture_assert(tctx, ok == true,
175                        "Failed to poll for tstream_unix_connect_send.");
176
177         rc = tstream_unix_connect_recv(req,
178                                        &sys_errno,
179                                        signd_client,
180                                        &signd_client->tstream);
181         TALLOC_FREE(req);
182         torture_assert(tctx, rc == 0, "Failed to connect to signd!");
183
184         /* Allocate the send queue */
185         signd_client->send_queue = tevent_queue_create(signd_client,
186                                                        "signd_client_queue");
187         torture_assert(tctx, signd_client->send_queue != NULL,
188                        "Failed to create send queue!");
189
190         /*
191          * Create the request buffer.
192          * First add the length of the request buffer
193          */
194         RSIVAL(signd_client->request_hdr, 0, sign_req_blob.length);
195         signd_client->request_iov[0].iov_base = signd_client->request_hdr;
196         signd_client->request_iov[0].iov_len = 4;
197
198         signd_client->request_iov[1].iov_base = sign_req_blob.data;
199         signd_client->request_iov[1].iov_len = sign_req_blob.length;
200
201         /* Fire the request buffer */
202         torture_comment(tctx, "Sending the request\n");
203         req = tstream_writev_queue_send(signd_client,
204                                         tctx->ev,
205                                         signd_client->tstream,
206                                         signd_client->send_queue,
207                                         signd_client->request_iov, 2);
208         torture_assert(tctx, req != NULL,
209                        "Failed to send the signd request.");
210
211         ok = tevent_req_poll(req, tctx->ev);
212         torture_assert(tctx, ok == true,
213                        "Failed to poll for tstream_writev_queue_send.");
214
215         rc = tstream_writev_queue_recv(req, &sys_errno);
216         TALLOC_FREE(req);
217         torture_assert(tctx, rc > 0, "Failed to send data");
218
219         /* Wait for a reply */
220         torture_comment(tctx, "Waiting for the reply\n");
221         req = tstream_read_pdu_blob_send(signd_client,
222                                          tctx->ev,
223                                          signd_client->tstream,
224                                          4, /*initial_read_size */
225                                          packet_full_request_u32,
226                                          NULL);
227         torture_assert(tctx, req != NULL,
228                        "Failed to setup a read for pdu_blob.");
229
230         ok = tevent_req_poll(req, tctx->ev);
231         torture_assert(tctx, ok == true,
232                        "Failed to poll for tstream_read_pdu_blob_send.");
233
234         signd_client->status = tstream_read_pdu_blob_recv(req,
235                                                           signd_client,
236                                                           &signd_client->reply);
237         torture_assert_ntstatus_ok(tctx, signd_client->status,
238                                    "Error reading signd_client reply packet");
239
240         /* Skip length header */
241         signd_client->reply.data += 4;
242         signd_client->reply.length -= 4;
243
244         /* Check if the reply buffer is valid */
245         torture_comment(tctx, "Validating the reply buffer\n");
246         ndr_err = ndr_pull_struct_blob_all(&signd_client->reply,
247                                            mem_ctx,
248                                            &signed_reply,
249                                            (ndr_pull_flags_fn_t)ndr_pull_signed_reply);
250         torture_assert(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err),
251                         ndr_map_error2string(ndr_err));
252
253         torture_assert_u64_equal(tctx, signed_reply.version,
254                                  NTP_SIGND_PROTOCOL_VERSION_0,
255                                  "Invalid Version");
256         torture_assert_u64_equal(tctx, signed_reply.packet_id,
257                                  sign_req.packet_id, "Invalid Packet ID");
258         torture_assert_u64_equal(tctx, signed_reply.op,
259                                  SIGNING_SUCCESS,
260                                  "Should have replied with signing success");
261         torture_assert_u64_equal(tctx, signed_reply.signed_packet.length,
262                                  sign_req.packet_to_sign.length + 20,
263                                  "Invalid reply length from signd");
264         torture_assert_u64_equal(tctx, rid,
265                                  IVAL(signed_reply.signed_packet.data,
266                                  sign_req.packet_to_sign.length),
267                                  "Incorrect RID in reply");
268
269         /* Check computed signature */
270         MD5Init(&ctx);
271         MD5Update(&ctx, pwhash->hash, sizeof(pwhash->hash));
272         MD5Update(&ctx, sign_req.packet_to_sign.data,
273                   sign_req.packet_to_sign.length);
274         MD5Final(sig, &ctx);
275
276         torture_assert_mem_equal(tctx,
277                                  &signed_reply.signed_packet.data[sign_req.packet_to_sign.length + 4],
278                                  sig, 16, "Signature on reply was incorrect!");
279
280         talloc_free(mem_ctx);
281
282         return true;
283 }
284
285 NTSTATUS torture_ntp_init(void)
286 {
287         struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "NTP");
288         struct torture_rpc_tcase *tcase;
289
290         tcase = torture_suite_add_machine_workstation_rpc_iface_tcase(suite, "SIGND",
291                                                                       &ndr_table_netlogon, TEST_MACHINE_NAME);
292
293         torture_rpc_tcase_add_test_creds(tcase, "ntp_signd", test_ntp_signd);
294
295         suite->description = talloc_strdup(suite, "NTP tests");
296
297         torture_register_suite(suite);
298
299         return NT_STATUS_OK;
300 }
301