~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/smb_server/smb2/negprot.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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)
 
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)
 
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)
 
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)
 
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)
 
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
}