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/torture.h"
24 #include "torture/smbtorture.h"
26 #include "lib/socket/socket.h"
27 #include "lib/stream/packet.h"
28 #include "auth/credentials/credentials.h"
29 #include "torture/rpc/rpc.h"
30 #include "torture/rpc/netlogon.h"
31 #include "../lib/crypto/crypto.h"
32 #include "libcli/auth/libcli_auth.h"
33 #include "librpc/gen_ndr/ndr_netlogon_c.h"
34 #include "librpc/gen_ndr/ndr_netlogon.h"
35 #include "librpc/gen_ndr/ndr_ntp_signd.h"
36 #include "param/param.h"
38 #define TEST_MACHINE_NAME "ntpsigndtest"
40 struct signd_client_socket
{
41 struct socket_context
*sock
;
44 struct tevent_fd
*fde
;
47 DATA_BLOB request
, reply
;
49 struct packet_context
*packet
;
54 static NTSTATUS
signd_client_full_packet(void *private_data
, DATA_BLOB data
)
56 struct signd_client_socket
*signd_client
= talloc_get_type(private_data
, struct signd_client_socket
);
57 talloc_steal(signd_client
, data
.data
);
58 signd_client
->reply
= data
;
59 signd_client
->reply
.length
-= 4;
60 signd_client
->reply
.data
+= 4;
64 static void signd_client_error_handler(void *private_data
, NTSTATUS status
)
66 struct signd_client_socket
*signd_client
= talloc_get_type(private_data
, struct signd_client_socket
);
67 signd_client
->status
= status
;
71 handle fd events on a signd_client_socket
73 static void signd_client_socket_handler(struct tevent_context
*ev
, struct tevent_fd
*fde
,
74 uint16_t flags
, void *private_data
)
76 struct signd_client_socket
*signd_client
= talloc_get_type(private_data
, struct signd_client_socket
);
77 if (flags
& TEVENT_FD_READ
) {
78 packet_recv(signd_client
->packet
);
81 if (flags
& TEVENT_FD_WRITE
) {
82 packet_queue_run(signd_client
->packet
);
89 /* A torture test to show that the unix domain socket protocol is
90 * operating correctly, and the signatures are as expected */
92 static bool test_ntp_signd(struct torture_context
*tctx
,
93 struct dcerpc_pipe
*p
,
94 struct cli_credentials
*credentials
)
96 struct netlogon_creds_CredentialState
*creds
;
97 TALLOC_CTX
*mem_ctx
= talloc_new(tctx
);
100 struct netr_ServerReqChallenge r
;
101 struct netr_ServerAuthenticate3 a
;
102 struct netr_Credential credentials1
, credentials2
, credentials3
;
104 const char *machine_name
;
105 const struct samr_Password
*pwhash
= cli_credentials_get_nt_hash(credentials
, mem_ctx
);
106 uint32_t negotiate_flags
= NETLOGON_NEG_AUTH2_ADS_FLAGS
;
108 struct sign_request sign_req
;
109 struct signed_reply signed_reply
;
110 DATA_BLOB sign_req_blob
;
112 struct signd_client_socket
*signd_client
;
113 char *signd_socket_address
;
115 struct MD5Context ctx
;
117 enum ndr_err_code ndr_err
;
119 machine_name
= cli_credentials_get_workstation(credentials
);
121 torture_comment(tctx
, "Testing ServerReqChallenge\n");
123 r
.in
.server_name
= NULL
;
124 r
.in
.computer_name
= machine_name
;
125 r
.in
.credentials
= &credentials1
;
126 r
.out
.return_credentials
= &credentials2
;
128 generate_random_buffer(credentials1
.data
, sizeof(credentials1
.data
));
130 status
= dcerpc_netr_ServerReqChallenge(p
, tctx
, &r
);
131 torture_assert_ntstatus_ok(tctx
, status
, "ServerReqChallenge");
133 a
.in
.server_name
= NULL
;
134 a
.in
.account_name
= talloc_asprintf(tctx
, "%s$", machine_name
);
135 a
.in
.secure_channel_type
= SEC_CHAN_WKSTA
;
136 a
.in
.computer_name
= machine_name
;
137 a
.in
.negotiate_flags
= &negotiate_flags
;
138 a
.in
.credentials
= &credentials3
;
139 a
.out
.return_credentials
= &credentials3
;
140 a
.out
.negotiate_flags
= &negotiate_flags
;
143 creds
= netlogon_creds_client_init(tctx
, a
.in
.account_name
,
145 &credentials1
, &credentials2
,
146 pwhash
, &credentials3
,
149 torture_assert(tctx
, creds
!= NULL
, "memory allocation");
151 torture_comment(tctx
, "Testing ServerAuthenticate3\n");
153 status
= dcerpc_netr_ServerAuthenticate3(p
, tctx
, &a
);
154 torture_assert_ntstatus_ok(tctx
, status
, "ServerAuthenticate3");
155 torture_assert(tctx
, netlogon_creds_client_check(creds
, &credentials3
), "Credential chaining failed");
157 sign_req
.op
= SIGN_TO_CLIENT
;
158 sign_req
.packet_id
= 1;
159 sign_req
.key_id
= rid
;
160 sign_req
.packet_to_sign
= data_blob_string_const("I am a tea pot");
162 ndr_err
= ndr_push_struct_blob(&sign_req_blob
, mem_ctx
, NULL
, &sign_req
, (ndr_push_flags_fn_t
)ndr_push_sign_request
);
163 torture_assert(tctx
, NDR_ERR_CODE_IS_SUCCESS(ndr_err
), "Failed to push sign_req");
165 signd_client
= talloc(mem_ctx
, struct signd_client_socket
);
167 status
= socket_create("unix", SOCKET_TYPE_STREAM
, &signd_client
->sock
, 0);
169 signd_socket_address
= talloc_asprintf(signd_client
, "%s/socket",
170 lp_ntp_signd_socket_directory(tctx
->lp_ctx
));
172 status
= socket_connect_ev(signd_client
->sock
, NULL
,
173 socket_address_from_strings(signd_client
,
174 "unix", signd_socket_address
, 0), 0, tctx
->ev
);
175 torture_assert_ntstatus_ok(tctx
, status
, "Failed to connect to signd!");
177 /* Setup the FDE, start listening for read events
178 * from the start (otherwise we may miss a socket
179 * drop) and mark as AUTOCLOSE along with the fde */
181 /* Ths is equivilant to EVENT_FD_READABLE(signd_client->fde) */
182 signd_client
->fde
= tevent_add_fd(tctx
->ev
, signd_client
->sock
,
183 socket_get_fd(signd_client
->sock
),
185 signd_client_socket_handler
, signd_client
);
186 /* its now the job of the event layer to close the socket */
187 tevent_fd_set_close_fn(signd_client
->fde
, socket_tevent_fd_close_fn
);
188 socket_set_flags(signd_client
->sock
, SOCKET_FLAG_NOCLOSE
);
190 signd_client
->status
= NT_STATUS_OK
;
191 signd_client
->reply
= data_blob(NULL
, 0);
193 signd_client
->packet
= packet_init(signd_client
);
194 if (signd_client
->packet
== NULL
) {
195 talloc_free(signd_client
);
198 packet_set_private(signd_client
->packet
, signd_client
);
199 packet_set_socket(signd_client
->packet
, signd_client
->sock
);
200 packet_set_callback(signd_client
->packet
, signd_client_full_packet
);
201 packet_set_full_request(signd_client
->packet
, packet_full_request_u32
);
202 packet_set_error_handler(signd_client
->packet
, signd_client_error_handler
);
203 packet_set_event_context(signd_client
->packet
, tctx
->ev
);
204 packet_set_fde(signd_client
->packet
, signd_client
->fde
);
206 signd_client
->request
= data_blob_talloc(signd_client
, NULL
, sign_req_blob
.length
+ 4);
207 RSIVAL(signd_client
->request
.data
, 0, sign_req_blob
.length
);
208 memcpy(signd_client
->request
.data
+4, sign_req_blob
.data
, sign_req_blob
.length
);
209 packet_send(signd_client
->packet
, signd_client
->request
);
211 while ((NT_STATUS_IS_OK(signd_client
->status
)) && !signd_client
->reply
.length
) {
212 if (tevent_loop_once(tctx
->ev
) != 0) {
213 talloc_free(signd_client
);
218 torture_assert_ntstatus_ok(tctx
, signd_client
->status
, "Error reading signd_client reply packet");
220 ndr_err
= ndr_pull_struct_blob_all(&signd_client
->reply
, mem_ctx
,
221 lp_iconv_convenience(tctx
->lp_ctx
),
223 (ndr_pull_flags_fn_t
)ndr_pull_signed_reply
);
224 torture_assert(tctx
, NDR_ERR_CODE_IS_SUCCESS(ndr_err
), ndr_map_error2string(ndr_err
));
226 torture_assert_u64_equal(tctx
, signed_reply
.version
,
227 NTP_SIGND_PROTOCOL_VERSION_0
, "Invalid Version");
228 torture_assert_u64_equal(tctx
, signed_reply
.packet_id
,
229 sign_req
.packet_id
, "Invalid Packet ID");
230 torture_assert_u64_equal(tctx
, signed_reply
.op
,
231 SIGNING_SUCCESS
, "Should have replied with signing success");
232 torture_assert_u64_equal(tctx
, signed_reply
.signed_packet
.length
,
233 sign_req
.packet_to_sign
.length
+ 20, "Invalid reply length from signd");
234 torture_assert_u64_equal(tctx
, rid
,
235 IVAL(signed_reply
.signed_packet
.data
, sign_req
.packet_to_sign
.length
),
236 "Incorrect RID in reply");
238 /* Check computed signature */
241 MD5Update(&ctx
, pwhash
->hash
, sizeof(pwhash
->hash
));
242 MD5Update(&ctx
, sign_req
.packet_to_sign
.data
, sign_req
.packet_to_sign
.length
);
245 torture_assert_mem_equal(tctx
, &signed_reply
.signed_packet
.data
[sign_req
.packet_to_sign
.length
+ 4],
246 sig
, 16, "Signature on reply was incorrect!");
248 talloc_free(mem_ctx
);
253 NTSTATUS
torture_ntp_init(void)
255 struct torture_suite
*suite
= torture_suite_create(talloc_autofree_context(), "NTP");
256 struct torture_rpc_tcase
*tcase
;
258 tcase
= torture_suite_add_machine_workstation_rpc_iface_tcase(suite
, "SIGND",
259 &ndr_table_netlogon
, TEST_MACHINE_NAME
);
261 torture_rpc_tcase_add_test_creds(tcase
, "ntp_signd", test_ntp_signd
);
263 suite
->description
= talloc_strdup(suite
, "NTP tests");
265 torture_register_suite(suite
);