root/source4/smb_server/smb2/negprot.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. smb2srv_negprot_secblob
  2. smb2srv_negprot_backend
  3. smb2srv_negprot_send
  4. smb2srv_negprot_recv
  5. smb2srv_reply_smb_negprot

   1 /* 
   2    Unix SMB2 implementation.
   3    
   4    Copyright (C) Andrew Bartlett        2001-2005
   5    Copyright (C) Stefan Metzmacher      2005
   6    
   7    This program is free software; you can redistribute it and/or modify
   8    it under the terms of the GNU General Public License as published by
   9    the Free Software Foundation; either version 3 of the License, or
  10    (at your option) any later version.
  11    
  12    This program is distributed in the hope that it will be useful,
  13    but WITHOUT ANY WARRANTY; without even the implied warranty of
  14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15    GNU General Public License for more details.
  16    
  17    You should have received a copy of the GNU General Public License
  18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  19 */
  20 
  21 #include "includes.h"
  22 #include "auth/credentials/credentials.h"
  23 #include "auth/auth.h"
  24 #include "auth/gensec/gensec.h"
  25 #include "libcli/raw/libcliraw.h"
  26 #include "libcli/raw/raw_proto.h"
  27 #include "libcli/smb2/smb2.h"
  28 #include "libcli/smb2/smb2_calls.h"
  29 #include "smb_server/smb_server.h"
  30 #include "smb_server/service_smb_proto.h"
  31 #include "smb_server/smb2/smb2_server.h"
  32 #include "smbd/service_stream.h"
  33 #include "param/param.h"
  34 #include "librpc/ndr/libndr.h"
  35 
  36 static NTSTATUS smb2srv_negprot_secblob(struct smb2srv_request *req, DATA_BLOB *_blob)
     /* [<][>][^][v][top][bottom][index][help] */
  37 {
  38         struct gensec_security *gensec_security;
  39         DATA_BLOB null_data_blob = data_blob(NULL, 0);
  40         DATA_BLOB blob;
  41         NTSTATUS nt_status;
  42         struct cli_credentials *server_credentials;
  43 
  44         server_credentials = cli_credentials_init(req);
  45         if (!server_credentials) {
  46                 smbsrv_terminate_connection(req->smb_conn, "Failed to init server credentials\n");
  47                 return NT_STATUS_NO_MEMORY;
  48         }
  49 
  50         cli_credentials_set_conf(server_credentials, req->smb_conn->lp_ctx);
  51         nt_status = cli_credentials_set_machine_account(server_credentials, req->smb_conn->lp_ctx);
  52         if (!NT_STATUS_IS_OK(nt_status)) {
  53                 DEBUG(10, ("Failed to obtain server credentials, perhaps a standalone server?: %s\n", nt_errstr(nt_status)));
  54                 talloc_free(server_credentials);
  55                 server_credentials = NULL;
  56         }
  57 
  58         req->smb_conn->negotiate.server_credentials = talloc_steal(req->smb_conn, server_credentials);
  59 
  60         nt_status = samba_server_gensec_start(req,
  61                                               req->smb_conn->connection->event.ctx,
  62                                               req->smb_conn->connection->msg_ctx,
  63                                               req->smb_conn->lp_ctx,
  64                                               server_credentials,
  65                                               "cifs",
  66                                               &gensec_security);
  67         if (!NT_STATUS_IS_OK(nt_status)) {
  68                 DEBUG(0, ("Failed to start GENSEC: %s\n", nt_errstr(nt_status)));
  69                 smbsrv_terminate_connection(req->smb_conn, "Failed to start GENSEC\n");
  70                 return nt_status;
  71         }
  72 
  73         gensec_set_target_service(gensec_security, "cifs");
  74 
  75         gensec_set_credentials(gensec_security, server_credentials);
  76 
  77         nt_status = gensec_start_mech_by_oid(gensec_security, GENSEC_OID_SPNEGO);
  78         if (!NT_STATUS_IS_OK(nt_status)) {
  79                 DEBUG(0, ("Failed to start SPNEGO: %s\n", nt_errstr(nt_status)));
  80                 smbsrv_terminate_connection(req->smb_conn, "Failed to start SPNEGO\n");
  81                 return nt_status;
  82         }
  83 
  84         nt_status = gensec_update(gensec_security, req, null_data_blob, &blob);
  85         if (!NT_STATUS_IS_OK(nt_status) && !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
  86                 DEBUG(0, ("Failed to get SPNEGO to give us the first token: %s\n", nt_errstr(nt_status)));
  87                 smbsrv_terminate_connection(req->smb_conn, "Failed to start SPNEGO - no first token\n");
  88                 return nt_status;
  89         }
  90 
  91         *_blob = blob;
  92         return NT_STATUS_OK;
  93 }
  94 
  95 static NTSTATUS smb2srv_negprot_backend(struct smb2srv_request *req, struct smb2_negprot *io)
     /* [<][>][^][v][top][bottom][index][help] */
  96 {
  97         NTSTATUS status;
  98         struct timeval current_time;
  99         struct timeval boot_time;
 100 
 101         /* we only do one dialect for now */
 102         if (io->in.dialect_count < 1) {
 103                 return NT_STATUS_NOT_SUPPORTED;
 104         }
 105         if (io->in.dialects[0] != 0 &&
 106             io->in.dialects[0] != SMB2_DIALECT_REVISION) {
 107                 DEBUG(0,("Got unexpected SMB2 dialect %u\n", io->in.dialects[0]));
 108                 return NT_STATUS_NOT_SUPPORTED;
 109         }
 110 
 111         req->smb_conn->negotiate.protocol = PROTOCOL_SMB2;
 112 
 113         current_time = timeval_current(); /* TODO: handle timezone?! */
 114         boot_time = timeval_current(); /* TODO: fix me */
 115 
 116         ZERO_STRUCT(io->out);
 117         switch (lp_server_signing(req->smb_conn->lp_ctx)) {
 118         case SMB_SIGNING_OFF:
 119                 io->out.security_mode = 0;
 120                 break;
 121         case SMB_SIGNING_SUPPORTED:
 122         case SMB_SIGNING_AUTO:
 123                 io->out.security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED;
 124                 break;
 125         case SMB_SIGNING_REQUIRED:
 126                 io->out.security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED;
 127                 /* force signing on immediately */
 128                 req->smb_conn->smb2_signing_required = true;
 129                 break;
 130         }
 131         io->out.dialect_revision   = SMB2_DIALECT_REVISION;
 132         io->out.capabilities       = 0;
 133         io->out.max_transact_size  = lp_parm_ulong(req->smb_conn->lp_ctx, NULL, 
 134                                                    "smb2", "max transaction size", 0x10000);
 135         io->out.max_read_size      = lp_parm_ulong(req->smb_conn->lp_ctx, NULL, 
 136                                                    "smb2", "max read size", 0x10000);
 137         io->out.max_write_size     = lp_parm_ulong(req->smb_conn->lp_ctx, NULL, 
 138                                                    "smb2", "max write size", 0x10000);
 139         io->out.system_time        = timeval_to_nttime(&current_time);
 140         io->out.server_start_time  = timeval_to_nttime(&boot_time);
 141         io->out.reserved2          = 0;
 142         status = smb2srv_negprot_secblob(req, &io->out.secblob);
 143         NT_STATUS_NOT_OK_RETURN(status);
 144 
 145         return NT_STATUS_OK;
 146 }
 147 
 148 static void smb2srv_negprot_send(struct smb2srv_request *req, struct smb2_negprot *io)
     /* [<][>][^][v][top][bottom][index][help] */
 149 {
 150         NTSTATUS status;
 151         enum ndr_err_code ndr_err;
 152 
 153         if (NT_STATUS_IS_ERR(req->status)) {
 154                 smb2srv_send_error(req, req->status); /* TODO: is this correct? */
 155                 return;
 156         }
 157 
 158         status = smb2srv_setup_reply(req, 0x40, true, io->out.secblob.length);
 159         if (!NT_STATUS_IS_OK(status)) {
 160                 smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
 161                 talloc_free(req);
 162                 return;
 163         }
 164 
 165         SSVAL(req->out.body, 0x02, io->out.security_mode);
 166         SIVAL(req->out.body, 0x04, io->out.dialect_revision);
 167         SIVAL(req->out.body, 0x06, io->out.reserved);
 168         ndr_err = smbcli_push_guid(req->out.body, 0x08, &io->out.server_guid);
 169         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 170                 smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
 171                 talloc_free(req);
 172                 return;
 173         }
 174         SIVAL(req->out.body, 0x18, io->out.capabilities);
 175         SIVAL(req->out.body, 0x1C, io->out.max_transact_size);
 176         SIVAL(req->out.body, 0x20, io->out.max_read_size);
 177         SIVAL(req->out.body, 0x24, io->out.max_write_size);
 178         push_nttime(req->out.body, 0x28, io->out.system_time);
 179         push_nttime(req->out.body, 0x30, io->out.server_start_time);
 180         SIVAL(req->out.body, 0x3C, io->out.reserved2);
 181         status = smb2_push_o16s16_blob(&req->out, 0x38, io->out.secblob);
 182         if (!NT_STATUS_IS_OK(status)) {
 183                 smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
 184                 talloc_free(req);
 185                 return;
 186         }
 187 
 188         smb2srv_send_reply(req);
 189 }
 190 
 191 void smb2srv_negprot_recv(struct smb2srv_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
 192 {
 193         struct smb2_negprot *io;
 194         int i;
 195         enum ndr_err_code ndr_err;
 196 
 197         if (req->in.body_size < 0x26) {
 198                 smbsrv_terminate_connection(req->smb_conn, "Bad body size in SMB2 negprot");
 199                 return;
 200         }
 201 
 202         io = talloc(req, struct smb2_negprot);
 203         if (!io) {
 204                 smbsrv_terminate_connection(req->smb_conn, nt_errstr(NT_STATUS_NO_MEMORY));
 205                 talloc_free(req);
 206                 return;
 207         }
 208 
 209         io->in.dialect_count = SVAL(req->in.body, 0x02);
 210         io->in.security_mode = SVAL(req->in.body, 0x04);
 211         io->in.reserved      = SVAL(req->in.body, 0x06);
 212         io->in.capabilities  = IVAL(req->in.body, 0x08);
 213         ndr_err = smbcli_pull_guid(req->in.body, 0xC, &io->in.client_guid);
 214         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 215                 smbsrv_terminate_connection(req->smb_conn, "Bad GUID in SMB2 negprot");
 216                 talloc_free(req);
 217                 return;
 218         }
 219         io->in.start_time = smbcli_pull_nttime(req->in.body, 0x1C);
 220 
 221         io->in.dialects = talloc_array(req, uint16_t, io->in.dialect_count);
 222         if (io->in.dialects == NULL) {
 223                 smbsrv_terminate_connection(req->smb_conn, nt_errstr(NT_STATUS_NO_MEMORY));
 224                 talloc_free(req);
 225                 return;
 226         }
 227         for (i=0;i<io->in.dialect_count;i++) {
 228                 io->in.dialects[i] = SVAL(req->in.body, 0x24+i*2);
 229         }
 230 
 231         req->status = smb2srv_negprot_backend(req, io);
 232 
 233         if (req->control_flags & SMB2SRV_REQ_CTRL_FLAG_NOT_REPLY) {
 234                 talloc_free(req);
 235                 return;
 236         }
 237         smb2srv_negprot_send(req, io);
 238 }
 239 
 240 /*
 241  * reply to a SMB negprot request with dialect "SMB 2.002"
 242  */
 243 void smb2srv_reply_smb_negprot(struct smbsrv_request *smb_req)
     /* [<][>][^][v][top][bottom][index][help] */
 244 {
 245         struct smb2srv_request *req;
 246         uint32_t body_fixed_size = 0x26;
 247 
 248         req = talloc_zero(smb_req->smb_conn, struct smb2srv_request);
 249         if (!req) goto nomem;
 250         req->smb_conn           = smb_req->smb_conn;
 251         req->request_time       = smb_req->request_time;
 252         talloc_steal(req, smb_req);
 253 
 254         req->in.size      = NBT_HDR_SIZE+SMB2_HDR_BODY+body_fixed_size;
 255         req->in.allocated = req->in.size;
 256         req->in.buffer    = talloc_array(req, uint8_t, req->in.allocated);
 257         if (!req->in.buffer) goto nomem;
 258         req->in.hdr       = req->in.buffer + NBT_HDR_SIZE;
 259         req->in.body      = req->in.hdr + SMB2_HDR_BODY;
 260         req->in.body_size = body_fixed_size;
 261         req->in.dynamic   = NULL;
 262 
 263         smb2srv_setup_bufinfo(req);
 264 
 265         SIVAL(req->in.hdr, 0,                           SMB2_MAGIC);
 266         SSVAL(req->in.hdr, SMB2_HDR_LENGTH,             SMB2_HDR_BODY);
 267         SSVAL(req->in.hdr, SMB2_HDR_EPOCH,              0);
 268         SIVAL(req->in.hdr, SMB2_HDR_STATUS,             0);
 269         SSVAL(req->in.hdr, SMB2_HDR_OPCODE,             SMB2_OP_NEGPROT);
 270         SSVAL(req->in.hdr, SMB2_HDR_CREDIT,             0);
 271         SIVAL(req->in.hdr, SMB2_HDR_FLAGS,              0);
 272         SIVAL(req->in.hdr, SMB2_HDR_NEXT_COMMAND,       0);
 273         SBVAL(req->in.hdr, SMB2_HDR_MESSAGE_ID,         0);
 274         SIVAL(req->in.hdr, SMB2_HDR_PID,                0);
 275         SIVAL(req->in.hdr, SMB2_HDR_TID,                0);
 276         SBVAL(req->in.hdr, SMB2_HDR_SESSION_ID,         0);
 277         memset(req->in.hdr+SMB2_HDR_SIGNATURE, 0, 16);
 278 
 279         /* this seems to be a bug, they use 0x24 but the length is 0x26 */
 280         SSVAL(req->in.body, 0x00, 0x24);
 281 
 282         SSVAL(req->in.body, 0x02, 1);
 283         memset(req->in.body+0x04, 0, 32);
 284         SSVAL(req->in.body, 0x24, 0);
 285 
 286         smb2srv_negprot_recv(req);
 287         return;
 288 nomem:
 289         smbsrv_terminate_connection(smb_req->smb_conn, nt_errstr(NT_STATUS_NO_MEMORY));
 290         talloc_free(req);
 291         return;
 292 }

/* [<][>][^][v][top][bottom][index][help] */