r3463: separated out some more headers (asn_1.h, messages.h, dlinklist.h and ioctl.h)
[samba.git] / source / 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 #include "asn_1.h"
27
28 /*
29   setup the OS, Lanman and domain portions of a session setup reply
30 */
31 static void sesssetup_common_strings(struct smbsrv_request *req,
32                                      char **os, char **lanman, char **domain)
33 {
34         (*os) = talloc_asprintf(req, "Unix");
35         (*lanman) = talloc_asprintf(req, "Samba %s", SAMBA_VERSION_STRING);
36         (*domain) = talloc_asprintf(req, "%s", lp_workgroup());
37 }
38
39
40 /*
41   handler for old style session setup
42 */
43 static NTSTATUS sesssetup_old(struct smbsrv_request *req, union smb_sesssetup *sess)
44 {
45         NTSTATUS status;
46         struct auth_usersupplied_info *user_info = NULL;
47         struct auth_serversupplied_info *server_info = NULL;
48         struct auth_session_info *session_info;
49
50         TALLOC_CTX *mem_ctx = talloc_named(req, 0, "NT1 session setup");
51         char *remote_machine;
52         if (!mem_ctx) {
53                 return NT_STATUS_NO_MEMORY;
54         }
55         
56         if (!req->smb_conn->negotiate.done_sesssetup) {
57                 req->smb_conn->negotiate.max_send = sess->old.in.bufsize;
58         }
59         
60         remote_machine = socket_get_peer_addr(req->smb_conn->connection->socket, mem_ctx);
61         status = make_user_info_for_reply_enc(req->smb_conn,
62                                               &user_info, 
63                                               sess->old.in.user, sess->old.in.domain,
64                                               remote_machine,
65                                               sess->old.in.password,
66                                               data_blob(NULL, 0));
67         if (!NT_STATUS_IS_OK(status)) {
68                 talloc_free(mem_ctx);
69                 return NT_STATUS_ACCESS_DENIED;
70         }
71
72         status = req->smb_conn->negotiate.auth_context->check_ntlm_password(req->smb_conn->negotiate.auth_context, 
73                                                                             user_info, 
74                                                                             mem_ctx, 
75                                                                             &server_info);
76         if (!NT_STATUS_IS_OK(status)) {
77                 talloc_free(mem_ctx);
78                 return nt_status_squash(status);
79         }
80
81         /* This references server_info into session_info */
82         status = make_session_info(req, server_info, &session_info);
83         talloc_free(mem_ctx);
84         if (!NT_STATUS_IS_OK(status)) {
85                 return nt_status_squash(status);
86         }
87
88         sess->old.out.action = 0;
89         sess->old.out.vuid = smbsrv_register_session(req->smb_conn, session_info, NULL);
90         if (sess->old.out.vuid == UID_FIELD_INVALID) {
91                 return NT_STATUS_ACCESS_DENIED;
92         }
93         sesssetup_common_strings(req, 
94                                  &sess->old.out.os,
95                                  &sess->old.out.lanman,
96                                  &sess->old.out.domain);
97
98         req->session = smbsrv_session_find(req->smb_conn, sess->old.out.vuid);
99
100         return NT_STATUS_OK;
101 }
102
103
104 /*
105   handler for NT1 style session setup
106 */
107 static NTSTATUS sesssetup_nt1(struct smbsrv_request *req, union smb_sesssetup *sess)
108 {
109         NTSTATUS status;
110         struct auth_usersupplied_info *user_info = NULL;
111         struct auth_serversupplied_info *server_info = NULL;
112         struct auth_session_info *session_info;
113         TALLOC_CTX *mem_ctx = talloc_named(req, 0, "NT1 session setup");
114         
115         if (!mem_ctx) {
116                 return NT_STATUS_NO_MEMORY;
117         }
118
119         if (!req->smb_conn->negotiate.done_sesssetup) {
120                 req->smb_conn->negotiate.max_send = sess->nt1.in.bufsize;
121                 req->smb_conn->negotiate.client_caps = sess->nt1.in.capabilities;
122         }
123
124         if (req->smb_conn->negotiate.spnego_negotiated) {
125                 struct auth_context *auth_context;
126
127                 if (sess->nt1.in.user && *sess->nt1.in.user) {
128                         return NT_STATUS_ACCESS_DENIED;
129                 } else {
130                         make_user_info_guest(req->smb_conn, &user_info);
131                 }
132                 
133                 status = make_auth_context_subsystem(req->smb_conn, &auth_context);
134
135                 if (!NT_STATUS_IS_OK(status)) {
136                         talloc_free(mem_ctx);
137                         return status;
138                 }
139                 
140                 status = auth_context->check_ntlm_password(auth_context, 
141                                                            user_info, 
142                                                            mem_ctx,
143                                                            &server_info);
144         } else {
145                 char *remote_machine;
146                 remote_machine = socket_get_peer_addr(req->smb_conn->connection->socket, mem_ctx);
147                 status = make_user_info_for_reply_enc(req->smb_conn,
148                                                       &user_info, 
149                                                       sess->nt1.in.user, sess->nt1.in.domain,
150                                                       remote_machine,
151                                                       sess->nt1.in.password1,
152                                                       sess->nt1.in.password2);
153                 if (!NT_STATUS_IS_OK(status)) {
154                         talloc_free(mem_ctx);
155                         return NT_STATUS_ACCESS_DENIED;
156                 }
157                 
158                 status = req->smb_conn->negotiate
159                         .auth_context->check_ntlm_password(req->smb_conn->negotiate
160                                                            .auth_context, 
161                                                            user_info, 
162                                                            req,
163                                                            &server_info);
164         }
165
166         if (!NT_STATUS_IS_OK(status)) {
167                 talloc_free(mem_ctx);
168                 return nt_status_squash(status);
169         }
170
171         /* This references server_info into session_info */
172         status = make_session_info(mem_ctx, server_info, &session_info);
173         if (!NT_STATUS_IS_OK(status)) {
174                 talloc_free(mem_ctx);
175                 return nt_status_squash(status);
176         }
177
178         sess->nt1.out.action = 0;
179         sess->nt1.out.vuid = smbsrv_register_session(req->smb_conn, session_info, NULL);
180         talloc_free(mem_ctx);
181         if (sess->nt1.out.vuid == UID_FIELD_INVALID) {
182                 return NT_STATUS_ACCESS_DENIED;
183         }
184         sesssetup_common_strings(req, 
185                                  &sess->nt1.out.os,
186                                  &sess->nt1.out.lanman,
187                                  &sess->nt1.out.domain);
188         
189         req->session = smbsrv_session_find(req->smb_conn, sess->nt1.out.vuid);
190         if (session_info->server_info->guest) {
191                 return NT_STATUS_OK;
192         }
193         if (!srv_setup_signing(req->smb_conn, &session_info->session_key, &sess->nt1.in.password2)) {
194                 /* Already signing, or disabled */
195                 return NT_STATUS_OK;
196         }
197                 
198         /* Force check of the request packet, now we know the session key */
199         req_signing_check_incoming(req);
200
201         srv_signing_restart(req->smb_conn,  &session_info->session_key, &sess->nt1.in.password2);
202
203         return NT_STATUS_OK;
204 }
205
206
207 /*
208   handler for SPNEGO style session setup
209 */
210 static NTSTATUS sesssetup_spnego(struct smbsrv_request *req, union smb_sesssetup *sess)
211 {
212         NTSTATUS status = NT_STATUS_ACCESS_DENIED;
213         struct smbsrv_session *smb_sess;
214         struct gensec_security *gensec_ctx = NULL;
215         struct auth_session_info *session_info = NULL;
216         uint16_t vuid;
217
218         if (!req->smb_conn->negotiate.done_sesssetup) {
219                 req->smb_conn->negotiate.max_send = sess->nt1.in.bufsize;
220                 req->smb_conn->negotiate.client_caps = sess->nt1.in.capabilities;
221         }
222
223         vuid = SVAL(req->in.hdr,HDR_UID);
224         smb_sess = smbsrv_session_find(req->smb_conn, vuid);
225         if (smb_sess && !smb_sess->session_info) {
226                 if (!smb_sess->gensec_ctx) {
227                         return NT_STATUS_INVALID_HANDLE;
228                 }
229
230                 status = gensec_update(smb_sess->gensec_ctx, req, sess->spnego.in.secblob, &sess->spnego.out.secblob);
231         } else {
232                 smb_sess = NULL;
233
234                 status = gensec_server_start(req->smb_conn, &gensec_ctx);
235                 if (!NT_STATUS_IS_OK(status)) {
236                         DEBUG(1, ("Failed to start GENSEC server code: %s\n", nt_errstr(status)));
237                         return status;
238                 }
239
240                 gensec_want_feature(gensec_ctx, GENSEC_WANT_SESSION_KEY);
241
242                 status = gensec_start_mech_by_oid(gensec_ctx, OID_SPNEGO);
243                 if (!NT_STATUS_IS_OK(status)) {
244                         DEBUG(1, ("Failed to start GENSEC SPNEGO server code: %s\n", nt_errstr(status)));
245                         return status;
246                 }
247
248                 status = gensec_update(gensec_ctx, req, sess->spnego.in.secblob, &sess->spnego.out.secblob);
249
250         }
251
252         if (!smb_sess) {
253                 vuid = smbsrv_register_session(req->smb_conn, 
254                                                session_info, gensec_ctx);
255                 if (vuid == UID_FIELD_INVALID) {
256                         return NT_STATUS_ACCESS_DENIED;
257                 }
258                 smb_sess = smbsrv_session_find(req->smb_conn, vuid);
259                 if (!smb_sess) {
260                         return NT_STATUS_FOOBAR;
261                 }
262         }
263
264         if (NT_STATUS_IS_OK(status)) {
265                 DATA_BLOB session_key;
266                 
267                 status = gensec_session_info(smb_sess->gensec_ctx, &smb_sess->session_info);
268                 if (!NT_STATUS_IS_OK(status)) {
269                         return status;
270                 }
271                 
272                 status = gensec_session_key(smb_sess->gensec_ctx, 
273                                             &session_key);
274                 if (NT_STATUS_IS_OK(status) 
275                     && !smb_sess->session_info->server_info->guest
276                     && srv_setup_signing(req->smb_conn, &session_key, NULL)) {
277                         /* Force check of the request packet, now we know the session key */
278                         req_signing_check_incoming(req);
279
280                         srv_signing_restart(req->smb_conn, &session_key, NULL);
281
282                 }
283         } else {
284                 status = nt_status_squash(status);
285                 if (smb_sess->gensec_ctx && 
286                     !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
287                         gensec_end(&smb_sess->gensec_ctx);
288                 }
289         }
290
291         sess->spnego.out.action = 0;
292         sess->spnego.out.vuid = vuid;
293         sesssetup_common_strings(req, 
294                                  &sess->spnego.out.os,
295                                  &sess->spnego.out.lanman,
296                                  &sess->spnego.out.domain);
297
298         return status;
299 }
300
301 /*
302   backend for sessionsetup call - this takes all 3 variants of the call
303 */
304 NTSTATUS sesssetup_backend(struct smbsrv_request *req, 
305                            union smb_sesssetup *sess)
306 {
307         NTSTATUS status = NT_STATUS_INVALID_LEVEL;
308
309         switch (sess->generic.level) {
310                 case RAW_SESSSETUP_GENERIC:
311                         status = NT_STATUS_INVALID_LEVEL;
312                         break;
313                 case RAW_SESSSETUP_OLD:
314                         status = sesssetup_old(req, sess);
315                         break;
316                 case RAW_SESSSETUP_NT1:
317                         status = sesssetup_nt1(req, sess);
318                         break;
319                 case RAW_SESSSETUP_SPNEGO:
320                         status = sesssetup_spnego(req, sess);
321                         break;
322         }
323
324         if (NT_STATUS_IS_OK(status)) {
325                 req->smb_conn->negotiate.done_sesssetup = True;
326         }
327
328         return status;
329 }
330
331