LCOV - code coverage report
Current view: top level - source4/torture/ntp - ntp_signd.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 101 119 84.9 %
Date: 2024-04-21 15:09:00 Functions: 2 2 100.0 %

          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             : 

Generated by: LCOV version 1.14