r3453: - split out the auth and popt includes
[kai/samba-autobuild/.git] / source4 / smb_server / sesssetup.c
1 /* 
2    Unix SMB/CIFS implementation.
3    handle SMBsessionsetup
4    Copyright (C) Andrew Tridgell 1998-2001
5    Copyright (C) Andrew Bartlett      2001
6    Copyright (C) Jim McDonough        2002
7    Copyright (C) Luke Howard          2003
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25 #include "auth/auth.h"
26
27 /*
28   setup the OS, Lanman and domain portions of a session setup reply
29 */
30 static void sesssetup_common_strings(struct smbsrv_request *req,
31                                      char **os, char **lanman, char **domain)
32 {
33         (*os) = talloc_asprintf(req, "Unix");
34         (*lanman) = talloc_asprintf(req, "Samba %s", SAMBA_VERSION_STRING);
35         (*domain) = talloc_asprintf(req, "%s", lp_workgroup());
36 }
37
38
39 /*
40   handler for old style session setup
41 */
42 static NTSTATUS sesssetup_old(struct smbsrv_request *req, union smb_sesssetup *sess)
43 {
44         NTSTATUS status;
45         struct auth_usersupplied_info *user_info = NULL;
46         struct auth_serversupplied_info *server_info = NULL;
47         struct auth_session_info *session_info;
48
49         TALLOC_CTX *mem_ctx = talloc_named(req, 0, "NT1 session setup");
50         char *remote_machine;
51         if (!mem_ctx) {
52                 return NT_STATUS_NO_MEMORY;
53         }
54         
55         if (!req->smb_conn->negotiate.done_sesssetup) {
56                 req->smb_conn->negotiate.max_send = sess->old.in.bufsize;
57         }
58         
59         remote_machine = socket_get_peer_addr(req->smb_conn->connection->socket, mem_ctx);
60         status = make_user_info_for_reply_enc(req->smb_conn,
61                                               &user_info, 
62                                               sess->old.in.user, sess->old.in.domain,
63                                               remote_machine,
64                                               sess->old.in.password,
65                                               data_blob(NULL, 0));
66         if (!NT_STATUS_IS_OK(status)) {
67                 talloc_free(mem_ctx);
68                 return NT_STATUS_ACCESS_DENIED;
69         }
70
71         status = req->smb_conn->negotiate.auth_context->check_ntlm_password(req->smb_conn->negotiate.auth_context, 
72                                                                             user_info, 
73                                                                             mem_ctx, 
74                                                                             &server_info);
75         if (!NT_STATUS_IS_OK(status)) {
76                 talloc_free(mem_ctx);
77                 return nt_status_squash(status);
78         }
79
80         /* This references server_info into session_info */
81         status = make_session_info(req, server_info, &session_info);
82         talloc_free(mem_ctx);
83         if (!NT_STATUS_IS_OK(status)) {
84                 return nt_status_squash(status);
85         }
86
87         sess->old.out.action = 0;
88         sess->old.out.vuid = smbsrv_register_session(req->smb_conn, session_info, NULL);
89         if (sess->old.out.vuid == UID_FIELD_INVALID) {
90                 return NT_STATUS_ACCESS_DENIED;
91         }
92         sesssetup_common_strings(req, 
93                                  &sess->old.out.os,
94                                  &sess->old.out.lanman,
95                                  &sess->old.out.domain);
96
97         req->session = smbsrv_session_find(req->smb_conn, sess->old.out.vuid);
98
99         return NT_STATUS_OK;
100 }
101
102
103 /*
104   handler for NT1 style session setup
105 */
106 static NTSTATUS sesssetup_nt1(struct smbsrv_request *req, union smb_sesssetup *sess)
107 {
108         NTSTATUS status;
109         struct auth_usersupplied_info *user_info = NULL;
110         struct auth_serversupplied_info *server_info = NULL;
111         struct auth_session_info *session_info;
112         TALLOC_CTX *mem_ctx = talloc_named(req, 0, "NT1 session setup");
113         
114         if (!mem_ctx) {
115                 return NT_STATUS_NO_MEMORY;
116         }
117
118         if (!req->smb_conn->negotiate.done_sesssetup) {
119                 req->smb_conn->negotiate.max_send = sess->nt1.in.bufsize;
120                 req->smb_conn->negotiate.client_caps = sess->nt1.in.capabilities;
121         }
122
123         if (req->smb_conn->negotiate.spnego_negotiated) {
124                 struct auth_context *auth_context;
125
126                 if (sess->nt1.in.user && *sess->nt1.in.user) {
127                         return NT_STATUS_ACCESS_DENIED;
128                 } else {
129                         make_user_info_guest(req->smb_conn, &user_info);
130                 }
131                 
132                 status = make_auth_context_subsystem(req->smb_conn, &auth_context);
133
134                 if (!NT_STATUS_IS_OK(status)) {
135                         talloc_free(mem_ctx);
136                         return status;
137                 }
138                 
139                 status = auth_context->check_ntlm_password(auth_context, 
140                                                            user_info, 
141                                                            mem_ctx,
142                                                            &server_info);
143         } else {
144                 char *remote_machine;
145                 remote_machine = socket_get_peer_addr(req->smb_conn->connection->socket, mem_ctx);
146                 status = make_user_info_for_reply_enc(req->smb_conn,
147                                                       &user_info, 
148                                                       sess->nt1.in.user, sess->nt1.in.domain,
149                                                       remote_machine,
150                                                       sess->nt1.in.password1,
151                                                       sess->nt1.in.password2);
152                 if (!NT_STATUS_IS_OK(status)) {
153                         talloc_free(mem_ctx);
154                         return NT_STATUS_ACCESS_DENIED;
155                 }
156                 
157                 status = req->smb_conn->negotiate
158                         .auth_context->check_ntlm_password(req->smb_conn->negotiate
159                                                            .auth_context, 
160                                                            user_info, 
161                                                            req,
162                                                            &server_info);
163         }
164
165         if (!NT_STATUS_IS_OK(status)) {
166                 talloc_free(mem_ctx);
167                 return nt_status_squash(status);
168         }
169
170         /* This references server_info into session_info */
171         status = make_session_info(mem_ctx, server_info, &session_info);
172         if (!NT_STATUS_IS_OK(status)) {
173                 talloc_free(mem_ctx);
174                 return nt_status_squash(status);
175         }
176
177         sess->nt1.out.action = 0;
178         sess->nt1.out.vuid = smbsrv_register_session(req->smb_conn, session_info, NULL);
179         talloc_free(mem_ctx);
180         if (sess->nt1.out.vuid == UID_FIELD_INVALID) {
181                 return NT_STATUS_ACCESS_DENIED;
182         }
183         sesssetup_common_strings(req, 
184                                  &sess->nt1.out.os,
185                                  &sess->nt1.out.lanman,
186                                  &sess->nt1.out.domain);
187         
188         req->session = smbsrv_session_find(req->smb_conn, sess->nt1.out.vuid);
189         if (session_info->server_info->guest) {
190                 return NT_STATUS_OK;
191         }
192         if (!srv_setup_signing(req->smb_conn, &session_info->session_key, &sess->nt1.in.password2)) {
193                 /* Already signing, or disabled */
194                 return NT_STATUS_OK;
195         }
196                 
197         /* Force check of the request packet, now we know the session key */
198         req_signing_check_incoming(req);
199
200         srv_signing_restart(req->smb_conn,  &session_info->session_key, &sess->nt1.in.password2);
201
202         return NT_STATUS_OK;
203 }
204
205
206 /*
207   handler for SPNEGO style session setup
208 */
209 static NTSTATUS sesssetup_spnego(struct smbsrv_request *req, union smb_sesssetup *sess)
210 {
211         NTSTATUS status = NT_STATUS_ACCESS_DENIED;
212         struct smbsrv_session *smb_sess;
213         struct gensec_security *gensec_ctx = NULL;
214         struct auth_session_info *session_info = NULL;
215         uint16_t vuid;
216
217         if (!req->smb_conn->negotiate.done_sesssetup) {
218                 req->smb_conn->negotiate.max_send = sess->nt1.in.bufsize;
219                 req->smb_conn->negotiate.client_caps = sess->nt1.in.capabilities;
220         }
221
222         vuid = SVAL(req->in.hdr,HDR_UID);
223         smb_sess = smbsrv_session_find(req->smb_conn, vuid);
224         if (smb_sess && !smb_sess->session_info) {
225                 if (!smb_sess->gensec_ctx) {
226                         return NT_STATUS_INVALID_HANDLE;
227                 }
228
229                 status = gensec_update(smb_sess->gensec_ctx, req, sess->spnego.in.secblob, &sess->spnego.out.secblob);
230         } else {
231                 smb_sess = NULL;
232
233                 status = gensec_server_start(req->smb_conn, &gensec_ctx);
234                 if (!NT_STATUS_IS_OK(status)) {
235                         DEBUG(1, ("Failed to start GENSEC server code: %s\n", nt_errstr(status)));
236                         return status;
237                 }
238
239                 gensec_want_feature(gensec_ctx, GENSEC_WANT_SESSION_KEY);
240
241                 status = gensec_start_mech_by_oid(gensec_ctx, OID_SPNEGO);
242                 if (!NT_STATUS_IS_OK(status)) {
243                         DEBUG(1, ("Failed to start GENSEC SPNEGO server code: %s\n", nt_errstr(status)));
244                         return status;
245                 }
246
247                 status = gensec_update(gensec_ctx, req, sess->spnego.in.secblob, &sess->spnego.out.secblob);
248
249         }
250
251         if (!smb_sess) {
252                 vuid = smbsrv_register_session(req->smb_conn, 
253                                                session_info, gensec_ctx);
254                 if (vuid == UID_FIELD_INVALID) {
255                         return NT_STATUS_ACCESS_DENIED;
256                 }
257                 smb_sess = smbsrv_session_find(req->smb_conn, vuid);
258                 if (!smb_sess) {
259                         return NT_STATUS_FOOBAR;
260                 }
261         }
262
263         if (NT_STATUS_IS_OK(status)) {
264                 DATA_BLOB session_key;
265                 
266                 status = gensec_session_info(smb_sess->gensec_ctx, &smb_sess->session_info);
267                 if (!NT_STATUS_IS_OK(status)) {
268                         return status;
269                 }
270                 
271                 status = gensec_session_key(smb_sess->gensec_ctx, 
272                                             &session_key);
273                 if (NT_STATUS_IS_OK(status) 
274                     && !smb_sess->session_info->server_info->guest
275                     && srv_setup_signing(req->smb_conn, &session_key, NULL)) {
276                         /* Force check of the request packet, now we know the session key */
277                         req_signing_check_incoming(req);
278
279                         srv_signing_restart(req->smb_conn, &session_key, NULL);
280
281                 }
282         } else {
283                 status = nt_status_squash(status);
284                 if (smb_sess->gensec_ctx && 
285                     !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
286                         gensec_end(&smb_sess->gensec_ctx);
287                 }
288         }
289
290         sess->spnego.out.action = 0;
291         sess->spnego.out.vuid = vuid;
292         sesssetup_common_strings(req, 
293                                  &sess->spnego.out.os,
294                                  &sess->spnego.out.lanman,
295                                  &sess->spnego.out.domain);
296
297         return status;
298 }
299
300 /*
301   backend for sessionsetup call - this takes all 3 variants of the call
302 */
303 NTSTATUS sesssetup_backend(struct smbsrv_request *req, 
304                            union smb_sesssetup *sess)
305 {
306         NTSTATUS status = NT_STATUS_INVALID_LEVEL;
307
308         switch (sess->generic.level) {
309                 case RAW_SESSSETUP_GENERIC:
310                         status = NT_STATUS_INVALID_LEVEL;
311                         break;
312                 case RAW_SESSSETUP_OLD:
313                         status = sesssetup_old(req, sess);
314                         break;
315                 case RAW_SESSSETUP_NT1:
316                         status = sesssetup_nt1(req, sess);
317                         break;
318                 case RAW_SESSSETUP_SPNEGO:
319                         status = sesssetup_spnego(req, sess);
320                         break;
321         }
322
323         if (NT_STATUS_IS_OK(status)) {
324                 req->smb_conn->negotiate.done_sesssetup = True;
325         }
326
327         return status;
328 }
329
330