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