2 Unix SMB/CIFS implementation.
4 Test NTP authentication support
6 Copyright (C) Andrew Bartlet <abartlet@samba.org> 2008
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.
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.
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/>.
23 #include "torture/smbtorture.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 "libcli/auth/libcli_auth.h"
30 #include "librpc/gen_ndr/ndr_netlogon_c.h"
31 #include "librpc/gen_ndr/ndr_ntp_signd.h"
32 #include "param/param.h"
33 #include "system/network.h"
34 #include "torture/ntp/proto.h"
36 #include <gnutls/gnutls.h>
37 #include <gnutls/crypto.h>
39 #define TEST_MACHINE_NAME "ntpsigndtest"
41 struct signd_client_state
{
42 struct tsocket_address
*local_address
;
43 struct tsocket_address
*remote_address
;
45 struct tstream_context
*tstream
;
46 struct tevent_queue
*send_queue
;
48 uint8_t request_hdr
[4];
49 struct iovec request_iov
[2];
57 * A torture test to show that the unix domain socket protocol is
58 * operating correctly, and the signatures are as expected
60 static bool test_ntp_signd(struct torture_context
*tctx
,
61 struct dcerpc_pipe
*p
,
62 struct cli_credentials
*credentials
)
64 struct netlogon_creds_CredentialState
*creds
;
65 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
67 struct netr_ServerReqChallenge r
;
68 struct netr_ServerAuthenticate3 a
;
69 struct netr_Credential credentials1
, credentials2
, credentials3
;
71 const char *machine_name
;
72 const struct samr_Password
*pwhash
= cli_credentials_get_nt_hash(credentials
, mem_ctx
);
73 uint32_t negotiate_flags
= NETLOGON_NEG_AUTH2_ADS_FLAGS
| NETLOGON_NEG_SUPPORTS_AES
;
75 struct sign_request sign_req
;
76 struct signed_reply signed_reply
;
77 DATA_BLOB sign_req_blob
;
79 struct signd_client_state
*signd_client
;
80 struct tevent_req
*req
;
84 gnutls_hash_hd_t hash_hnd
;
86 enum ndr_err_code ndr_err
;
90 machine_name
= cli_credentials_get_workstation(credentials
);
92 torture_comment(tctx
, "Testing ServerReqChallenge\n");
94 r
.in
.server_name
= NULL
;
95 r
.in
.computer_name
= machine_name
;
96 r
.in
.credentials
= &credentials1
;
97 r
.out
.return_credentials
= &credentials2
;
99 generate_random_buffer(credentials1
.data
, sizeof(credentials1
.data
));
101 torture_assert_ntstatus_ok(tctx
,
102 dcerpc_netr_ServerReqChallenge_r(p
->binding_handle
, tctx
, &r
),
103 "ServerReqChallenge failed");
104 torture_assert_ntstatus_ok(tctx
, r
.out
.result
,
105 "ServerReqChallenge failed");
107 a
.in
.server_name
= NULL
;
108 a
.in
.account_name
= talloc_asprintf(tctx
, "%s$", machine_name
);
109 a
.in
.secure_channel_type
= SEC_CHAN_WKSTA
;
110 a
.in
.computer_name
= machine_name
;
111 a
.in
.negotiate_flags
= &negotiate_flags
;
112 a
.in
.credentials
= &credentials3
;
113 a
.out
.return_credentials
= &credentials3
;
114 a
.out
.negotiate_flags
= &negotiate_flags
;
117 creds
= netlogon_creds_client_init(tctx
, a
.in
.account_name
,
119 a
.in
.secure_channel_type
,
120 &credentials1
, &credentials2
,
121 pwhash
, &credentials3
,
124 torture_assert(tctx
, creds
!= NULL
, "memory allocation");
126 torture_comment(tctx
, "Testing ServerAuthenticate3\n");
128 torture_assert_ntstatus_ok(tctx
,
129 dcerpc_netr_ServerAuthenticate3_r(p
->binding_handle
, tctx
, &a
),
130 "ServerAuthenticate3 failed");
131 torture_assert_ntstatus_ok(tctx
, a
.out
.result
,
132 "ServerAuthenticate3 failed");
134 netlogon_creds_client_check(creds
, &credentials3
),
135 "Credential chaining failed");
137 sign_req
.op
= SIGN_TO_CLIENT
;
138 sign_req
.packet_id
= 1;
139 sign_req
.key_id
= rid
;
140 sign_req
.packet_to_sign
= data_blob_string_const("I am a tea pot");
142 ndr_err
= ndr_push_struct_blob(&sign_req_blob
,
145 (ndr_push_flags_fn_t
)ndr_push_sign_request
);
147 NDR_ERR_CODE_IS_SUCCESS(ndr_err
),
148 "Failed to push sign_req");
150 signd_client
= talloc(mem_ctx
, struct signd_client_state
);
152 /* Create socket addresses */
153 torture_comment(tctx
, "Creating the socket addresses\n");
154 rc
= tsocket_address_unix_from_path(signd_client
, "",
155 &signd_client
->local_address
);
156 torture_assert(tctx
, rc
== 0,
157 "Failed to create local address from unix path.");
159 unix_address
= talloc_asprintf(signd_client
,
161 lpcfg_ntp_signd_socket_directory(tctx
->lp_ctx
));
162 rc
= tsocket_address_unix_from_path(mem_ctx
,
164 &signd_client
->remote_address
);
165 torture_assert(tctx
, rc
== 0,
166 "Failed to create remote address from unix path.");
168 /* Connect to the unix socket */
169 torture_comment(tctx
, "Connecting to the unix socket\n");
170 req
= tstream_unix_connect_send(signd_client
,
172 signd_client
->local_address
,
173 signd_client
->remote_address
);
174 torture_assert(tctx
, req
!= NULL
,
175 "Failed to create a tstream unix connect request.");
177 ok
= tevent_req_poll(req
, tctx
->ev
);
178 torture_assert(tctx
, ok
== true,
179 "Failed to poll for tstream_unix_connect_send.");
181 rc
= tstream_unix_connect_recv(req
,
184 &signd_client
->tstream
);
186 torture_assert(tctx
, rc
== 0, "Failed to connect to signd!");
188 /* Allocate the send queue */
189 signd_client
->send_queue
= tevent_queue_create(signd_client
,
190 "signd_client_queue");
191 torture_assert(tctx
, signd_client
->send_queue
!= NULL
,
192 "Failed to create send queue!");
195 * Create the request buffer.
196 * First add the length of the request buffer
198 RSIVAL(signd_client
->request_hdr
, 0, sign_req_blob
.length
);
199 signd_client
->request_iov
[0].iov_base
= (char *) signd_client
->request_hdr
;
200 signd_client
->request_iov
[0].iov_len
= 4;
202 signd_client
->request_iov
[1].iov_base
= (char *) sign_req_blob
.data
;
203 signd_client
->request_iov
[1].iov_len
= sign_req_blob
.length
;
205 /* Fire the request buffer */
206 torture_comment(tctx
, "Sending the request\n");
207 req
= tstream_writev_queue_send(signd_client
,
209 signd_client
->tstream
,
210 signd_client
->send_queue
,
211 signd_client
->request_iov
, 2);
212 torture_assert(tctx
, req
!= NULL
,
213 "Failed to send the signd request.");
215 ok
= tevent_req_poll(req
, tctx
->ev
);
216 torture_assert(tctx
, ok
== true,
217 "Failed to poll for tstream_writev_queue_send.");
219 rc
= tstream_writev_queue_recv(req
, &sys_errno
);
221 torture_assert(tctx
, rc
> 0, "Failed to send data");
223 /* Wait for a reply */
224 torture_comment(tctx
, "Waiting for the reply\n");
225 req
= tstream_read_pdu_blob_send(signd_client
,
227 signd_client
->tstream
,
228 4, /*initial_read_size */
229 tstream_full_request_u32
,
231 torture_assert(tctx
, req
!= NULL
,
232 "Failed to setup a read for pdu_blob.");
234 ok
= tevent_req_poll(req
, tctx
->ev
);
235 torture_assert(tctx
, ok
== true,
236 "Failed to poll for tstream_read_pdu_blob_send.");
238 signd_client
->status
= tstream_read_pdu_blob_recv(req
,
240 &signd_client
->reply
);
241 torture_assert_ntstatus_ok(tctx
, signd_client
->status
,
242 "Error reading signd_client reply packet");
244 /* Skip length header */
245 signd_client
->reply
.data
+= 4;
246 signd_client
->reply
.length
-= 4;
248 /* Check if the reply buffer is valid */
249 torture_comment(tctx
, "Validating the reply buffer\n");
250 ndr_err
= ndr_pull_struct_blob_all(&signd_client
->reply
,
253 (ndr_pull_flags_fn_t
)ndr_pull_signed_reply
);
254 torture_assert(tctx
, NDR_ERR_CODE_IS_SUCCESS(ndr_err
),
255 ndr_map_error2string(ndr_err
));
257 torture_assert_u64_equal(tctx
, signed_reply
.version
,
258 NTP_SIGND_PROTOCOL_VERSION_0
,
260 torture_assert_u64_equal(tctx
, signed_reply
.packet_id
,
261 sign_req
.packet_id
, "Invalid Packet ID");
262 torture_assert_u64_equal(tctx
, signed_reply
.op
,
264 "Should have replied with signing success");
265 torture_assert_u64_equal(tctx
, signed_reply
.signed_packet
.length
,
266 sign_req
.packet_to_sign
.length
+ 20,
267 "Invalid reply length from signd");
268 torture_assert_u64_equal(tctx
, rid
,
269 IVAL(signed_reply
.signed_packet
.data
,
270 sign_req
.packet_to_sign
.length
),
271 "Incorrect RID in reply");
273 /* Check computed signature */
274 gnutls_hash_init(&hash_hnd
, GNUTLS_DIG_MD5
);
275 gnutls_hash(hash_hnd
, pwhash
->hash
, sizeof(pwhash
->hash
));
276 gnutls_hash(hash_hnd
,
277 sign_req
.packet_to_sign
.data
,
278 sign_req
.packet_to_sign
.length
);
279 gnutls_hash_deinit(hash_hnd
, sig
);
281 torture_assert_mem_equal(tctx
,
282 &signed_reply
.signed_packet
.data
[sign_req
.packet_to_sign
.length
+ 4],
283 sig
, 16, "Signature on reply was incorrect!");
285 talloc_free(mem_ctx
);
290 NTSTATUS
torture_ntp_init(TALLOC_CTX
*ctx
)
292 struct torture_suite
*suite
= torture_suite_create(ctx
, "ntp");
293 struct torture_rpc_tcase
*tcase
;
295 tcase
= torture_suite_add_machine_workstation_rpc_iface_tcase(suite
,
296 "signd", &ndr_table_netlogon
, TEST_MACHINE_NAME
);
298 torture_rpc_tcase_add_test_creds(tcase
, "ntp_signd", test_ntp_signd
);
300 suite
->description
= talloc_strdup(suite
, "NTP tests");
302 torture_register_suite(ctx
, suite
);