~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/libcli/smb2/session.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 SMB/CIFS implementation.
 
3
 
 
4
   SMB2 client session handling
 
5
 
 
6
   Copyright (C) Andrew Tridgell 2005
 
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 "libcli/raw/libcliraw.h"
 
24
#include "libcli/smb2/smb2.h"
 
25
#include "libcli/smb2/smb2_calls.h"
 
26
#include "libcli/composite/composite.h"
 
27
#include "auth/gensec/gensec.h"
 
28
 
 
29
/**
 
30
  initialise a smb2_session structure
 
31
 */
 
32
struct smb2_session *smb2_session_init(struct smb2_transport *transport,
 
33
                                       struct gensec_settings *settings,
 
34
                                       TALLOC_CTX *parent_ctx, bool primary)
 
35
{
 
36
        struct smb2_session *session;
 
37
        NTSTATUS status;
 
38
 
 
39
        session = talloc_zero(parent_ctx, struct smb2_session);
 
40
        if (!session) {
 
41
                return NULL;
 
42
        }
 
43
        if (primary) {
 
44
                session->transport = talloc_steal(session, transport);
 
45
        } else {
 
46
                session->transport = talloc_reference(session, transport);
 
47
        }
 
48
 
 
49
        /* prepare a gensec context for later use */
 
50
        status = gensec_client_start(session, &session->gensec, 
 
51
                                     session->transport->socket->event.ctx, 
 
52
                                     settings);
 
53
        if (!NT_STATUS_IS_OK(status)) {
 
54
                talloc_free(session);
 
55
                return NULL;
 
56
        }
 
57
 
 
58
        gensec_want_feature(session->gensec, GENSEC_FEATURE_SESSION_KEY);
 
59
 
 
60
        return session;
 
61
}
 
62
 
 
63
/**
 
64
  send a session setup request
 
65
*/
 
66
struct smb2_request *smb2_session_setup_send(struct smb2_session *session, 
 
67
                                             struct smb2_session_setup *io)
 
68
{
 
69
        struct smb2_request *req;
 
70
        NTSTATUS status;
 
71
        
 
72
        req = smb2_request_init(session->transport, SMB2_OP_SESSSETUP, 
 
73
                                0x18, true, io->in.secblob.length);
 
74
        if (req == NULL) return NULL;
 
75
 
 
76
        SBVAL(req->out.hdr,  SMB2_HDR_SESSION_ID, session->uid);
 
77
        SCVAL(req->out.body, 0x02, io->in.vc_number);
 
78
        SCVAL(req->out.body, 0x03, io->in.security_mode);
 
79
        SIVAL(req->out.body, 0x04, io->in.capabilities);
 
80
        SIVAL(req->out.body, 0x08, io->in.channel);
 
81
        SBVAL(req->out.body, 0x10, io->in.previous_sessionid);
 
82
 
 
83
        req->session = session;
 
84
 
 
85
        status = smb2_push_o16s16_blob(&req->out, 0x0C, io->in.secblob);
 
86
        if (!NT_STATUS_IS_OK(status)) {
 
87
                talloc_free(req);
 
88
                return NULL;
 
89
        }
 
90
 
 
91
        smb2_transport_send(req);
 
92
 
 
93
        return req;
 
94
}
 
95
 
 
96
 
 
97
/**
 
98
  recv a session setup reply
 
99
*/
 
100
NTSTATUS smb2_session_setup_recv(struct smb2_request *req, TALLOC_CTX *mem_ctx, 
 
101
                                 struct smb2_session_setup *io)
 
102
{
 
103
        NTSTATUS status;
 
104
 
 
105
        if (!smb2_request_receive(req) || 
 
106
            (smb2_request_is_error(req) && 
 
107
             !NT_STATUS_EQUAL(req->status, NT_STATUS_MORE_PROCESSING_REQUIRED))) {
 
108
                return smb2_request_destroy(req);
 
109
        }
 
110
 
 
111
        SMB2_CHECK_PACKET_RECV(req, 0x08, true);
 
112
 
 
113
        io->out.session_flags = SVAL(req->in.body, 0x02);
 
114
        io->out.uid           = BVAL(req->in.hdr,  SMB2_HDR_SESSION_ID);
 
115
        
 
116
        status = smb2_pull_o16s16_blob(&req->in, mem_ctx, req->in.body+0x04, &io->out.secblob);
 
117
        if (!NT_STATUS_IS_OK(status)) {
 
118
                smb2_request_destroy(req);
 
119
                return status;
 
120
        }
 
121
 
 
122
        return smb2_request_destroy(req);
 
123
}
 
124
 
 
125
/*
 
126
  sync session setup request
 
127
*/
 
128
NTSTATUS smb2_session_setup(struct smb2_session *session, 
 
129
                            TALLOC_CTX *mem_ctx, struct smb2_session_setup *io)
 
130
{
 
131
        struct smb2_request *req = smb2_session_setup_send(session, io);
 
132
        return smb2_session_setup_recv(req, mem_ctx, io);
 
133
}
 
134
 
 
135
 
 
136
struct smb2_session_state {
 
137
        struct smb2_session_setup io;
 
138
        struct smb2_request *req;
 
139
        NTSTATUS gensec_status;
 
140
};
 
141
 
 
142
/*
 
143
  handle continuations of the spnego session setup
 
144
*/
 
145
static void session_request_handler(struct smb2_request *req)
 
146
{
 
147
        struct composite_context *c = talloc_get_type(req->async.private_data, 
 
148
                                                      struct composite_context);
 
149
        struct smb2_session_state *state = talloc_get_type(c->private_data, 
 
150
                                                           struct smb2_session_state);
 
151
        struct smb2_session *session = req->session;
 
152
 
 
153
        c->status = smb2_session_setup_recv(req, c, &state->io);
 
154
        if (NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED) ||
 
155
            (NT_STATUS_IS_OK(c->status) && 
 
156
             NT_STATUS_EQUAL(state->gensec_status, NT_STATUS_MORE_PROCESSING_REQUIRED))) {
 
157
                NTSTATUS session_key_err;
 
158
                DATA_BLOB session_key;
 
159
                c->status = gensec_update(session->gensec, c, 
 
160
                                          state->io.out.secblob,
 
161
                                          &state->io.in.secblob);
 
162
                state->gensec_status = c->status;
 
163
 
 
164
                session_key_err = gensec_session_key(session->gensec, &session_key);
 
165
                if (NT_STATUS_IS_OK(session_key_err)) {
 
166
                        session->session_key = session_key;
 
167
                }               
 
168
        }
 
169
 
 
170
        session->uid = state->io.out.uid;
 
171
 
 
172
        if (NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
 
173
                state->req = smb2_session_setup_send(session, &state->io);
 
174
                if (state->req == NULL) {
 
175
                        composite_error(c, NT_STATUS_NO_MEMORY);
 
176
                        return;
 
177
                }
 
178
 
 
179
                state->req->async.fn = session_request_handler;
 
180
                state->req->async.private_data = c;
 
181
                return;
 
182
        }
 
183
 
 
184
        if (!NT_STATUS_IS_OK(c->status)) {
 
185
                composite_error(c, c->status);
 
186
                return;
 
187
        }
 
188
 
 
189
        if (session->transport->signing_required) {
 
190
                if (session->session_key.length == 0) {
 
191
                        DEBUG(0,("Wrong session key length %u for SMB2 signing\n",
 
192
                                 (unsigned)session->session_key.length));
 
193
                        composite_error(c, NT_STATUS_ACCESS_DENIED);
 
194
                        return;
 
195
                }
 
196
                session->signing_active = true;
 
197
        }
 
198
 
 
199
        composite_done(c);
 
200
}
 
201
 
 
202
/*
 
203
  a composite function that does a full SPNEGO session setup
 
204
 */
 
205
struct composite_context *smb2_session_setup_spnego_send(struct smb2_session *session, 
 
206
                                                         struct cli_credentials *credentials)
 
207
{
 
208
        struct composite_context *c;
 
209
        struct smb2_session_state *state;
 
210
 
 
211
        c = composite_create(session, session->transport->socket->event.ctx);
 
212
        if (c == NULL) return NULL;
 
213
 
 
214
        state = talloc(c, struct smb2_session_state);
 
215
        if (composite_nomem(state, c)) return c;
 
216
        c->private_data = state;
 
217
 
 
218
        ZERO_STRUCT(state->io);
 
219
        state->io.in.vc_number          = 0;
 
220
        if (session->transport->signing_required) {
 
221
                state->io.in.security_mode = 
 
222
                        SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED;
 
223
        }
 
224
        state->io.in.capabilities       = 0;
 
225
        state->io.in.channel            = 0;
 
226
        state->io.in.previous_sessionid = 0;
 
227
 
 
228
        c->status = gensec_set_credentials(session->gensec, credentials);
 
229
        if (!composite_is_ok(c)) return c;
 
230
 
 
231
        c->status = gensec_set_target_hostname(session->gensec, 
 
232
                                               session->transport->socket->hostname);
 
233
        if (!composite_is_ok(c)) return c;
 
234
 
 
235
        c->status = gensec_set_target_service(session->gensec, "cifs");
 
236
        if (!composite_is_ok(c)) return c;
 
237
 
 
238
        c->status = gensec_start_mech_by_oid(session->gensec, GENSEC_OID_SPNEGO);
 
239
        if (!composite_is_ok(c)) return c;
 
240
 
 
241
        c->status = gensec_update(session->gensec, c, 
 
242
                                  session->transport->negotiate.secblob,
 
243
                                  &state->io.in.secblob);
 
244
        if (!NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
 
245
                composite_error(c, c->status);
 
246
                return c;
 
247
        }
 
248
        state->gensec_status = c->status;
 
249
                
 
250
        state->req = smb2_session_setup_send(session, &state->io);
 
251
        composite_continue_smb2(c, state->req, session_request_handler, c);
 
252
        return c;
 
253
}
 
254
 
 
255
/*
 
256
  receive a composite session setup reply
 
257
*/
 
258
NTSTATUS smb2_session_setup_spnego_recv(struct composite_context *c)
 
259
{
 
260
        NTSTATUS status;
 
261
        status = composite_wait(c);
 
262
        talloc_free(c);
 
263
        return status;
 
264
}
 
265
 
 
266
/*
 
267
  sync version of smb2_session_setup_spnego
 
268
*/
 
269
NTSTATUS smb2_session_setup_spnego(struct smb2_session *session, 
 
270
                                   struct cli_credentials *credentials)
 
271
{
 
272
        struct composite_context *c = smb2_session_setup_spnego_send(session, credentials);
 
273
        return smb2_session_setup_spnego_recv(c);
 
274
}