s3:smbd: rework reply_spnego_ntlmssp to reply_spnego_generic
[metze/samba/wip.git] / source3 / smbd / 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 <jmcd@us.ibm.com> 2002
7    Copyright (C) Luke Howard          2003
8    Copyright (C) Volker Lendecke      2007
9    Copyright (C) Jeremy Allison       2007
10
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 3 of the License, or
14    (at your option) any later version.
15
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20
21    You should have received a copy of the GNU General Public License
22    along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 */
24
25 #include "includes.h"
26 #include "../lib/tsocket/tsocket.h"
27 #include "smbd/smbd.h"
28 #include "smbd/globals.h"
29 #include "../libcli/auth/spnego.h"
30 #include "../auth/ntlmssp/ntlmssp.h"
31 #include "../librpc/gen_ndr/krb5pac.h"
32 #include "libads/kerberos_proto.h"
33 #include "../lib/util/asn1.h"
34 #include "auth.h"
35 #include "messages.h"
36 #include "smbprofile.h"
37 #include "../libcli/security/security.h"
38 #include "auth/gensec/gensec.h"
39
40 /****************************************************************************
41  Add the standard 'Samba' signature to the end of the session setup.
42 ****************************************************************************/
43
44 static int push_signature(uint8 **outbuf)
45 {
46         char *lanman;
47         int result, tmp;
48
49         result = 0;
50
51         tmp = message_push_string(outbuf, "Unix", STR_TERMINATE);
52
53         if (tmp == -1) return -1;
54         result += tmp;
55
56         if (asprintf(&lanman, "Samba %s", samba_version_string()) != -1) {
57                 tmp = message_push_string(outbuf, lanman, STR_TERMINATE);
58                 SAFE_FREE(lanman);
59         }
60         else {
61                 tmp = message_push_string(outbuf, "Samba", STR_TERMINATE);
62         }
63
64         if (tmp == -1) return -1;
65         result += tmp;
66
67         tmp = message_push_string(outbuf, lp_workgroup(), STR_TERMINATE);
68
69         if (tmp == -1) return -1;
70         result += tmp;
71
72         return result;
73 }
74
75 /****************************************************************************
76  Send a security blob via a session setup reply.
77 ****************************************************************************/
78
79 static void reply_sesssetup_blob(struct smb_request *req,
80                                  DATA_BLOB blob,
81                                  NTSTATUS nt_status)
82 {
83         if (!NT_STATUS_IS_OK(nt_status) &&
84             !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
85                 reply_nterror(req, nt_status_squash(nt_status));
86                 return;
87         }
88
89         nt_status = nt_status_squash(nt_status);
90         SIVAL(req->outbuf, smb_rcls, NT_STATUS_V(nt_status));
91         SSVAL(req->outbuf, smb_vwv0, 0xFF); /* no chaining possible */
92         SSVAL(req->outbuf, smb_vwv3, blob.length);
93
94         if ((message_push_blob(&req->outbuf, blob) == -1)
95             || (push_signature(&req->outbuf) == -1)) {
96                 reply_nterror(req, NT_STATUS_NO_MEMORY);
97         }
98 }
99
100 /****************************************************************************
101  Do a 'guest' logon, getting back the
102 ****************************************************************************/
103
104 static NTSTATUS check_guest_password(const struct tsocket_address *remote_address,
105                                      struct auth_serversupplied_info **server_info)
106 {
107         struct auth_context *auth_context;
108         struct auth_usersupplied_info *user_info = NULL;
109
110         NTSTATUS nt_status;
111         static unsigned char chal[8] = { 0, };
112
113         DEBUG(3,("Got anonymous request\n"));
114
115         nt_status = make_auth_context_fixed(talloc_tos(), &auth_context, chal);
116         if (!NT_STATUS_IS_OK(nt_status)) {
117                 return nt_status;
118         }
119
120         if (!make_user_info_guest(remote_address, &user_info)) {
121                 TALLOC_FREE(auth_context);
122                 return NT_STATUS_NO_MEMORY;
123         }
124
125         nt_status = auth_context->check_ntlm_password(auth_context,
126                                                 user_info,
127                                                 server_info);
128         TALLOC_FREE(auth_context);
129         free_user_info(&user_info);
130         return nt_status;
131 }
132
133 static void reply_spnego_generic(struct smb_request *req,
134                                  uint16 vuid,
135                                  struct gensec_security **gensec_security,
136                                  DATA_BLOB *blob, NTSTATUS nt_status)
137 {
138         bool do_invalidate = true;
139         struct auth_session_info *session_info = NULL;
140         struct smbd_server_connection *sconn = req->sconn;
141
142         if (NT_STATUS_IS_OK(nt_status)) {
143                 nt_status = gensec_session_info(*gensec_security,
144                                                 talloc_tos(),
145                                                 &session_info);
146         }
147
148         reply_outbuf(req, 4, 0);
149
150         SSVAL(req->outbuf, smb_uid, vuid);
151
152         if (NT_STATUS_IS_OK(nt_status)) {
153                 DATA_BLOB nullblob = data_blob_null;
154
155                 if (!is_partial_auth_vuid(sconn, vuid)) {
156                         nt_status = NT_STATUS_LOGON_FAILURE;
157                         goto out;
158                 }
159
160                 /* register_existing_vuid keeps the server info */
161                 if (register_existing_vuid(sconn, vuid,
162                                            session_info, nullblob) !=
163                                            vuid) {
164                         /* The problem is, *gensec_security points
165                          * into the vuser this will have
166                          * talloc_free()'ed in
167                          * register_existing_vuid() */
168                         do_invalidate = false;
169                         nt_status = NT_STATUS_LOGON_FAILURE;
170                         goto out;
171                 }
172
173                 /* current_user_info is changed on new vuid */
174                 reload_services(sconn, conn_snum_used, true);
175
176                 SSVAL(req->outbuf, smb_vwv3, 0);
177
178                 if (security_session_user_level(session_info, NULL) < SECURITY_USER) {
179                         SSVAL(req->outbuf,smb_vwv2,1);
180                 }
181         }
182
183   out:
184
185         reply_sesssetup_blob(req, *blob, nt_status);
186
187         /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
188            and the other end, that we are not finished yet. */
189
190         if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
191                 /* NB. This is *NOT* an error case. JRA */
192                 if (do_invalidate) {
193                         TALLOC_FREE(*gensec_security);
194                         if (!NT_STATUS_IS_OK(nt_status)) {
195                                 /* Kill the intermediate vuid */
196                                 invalidate_vuid(sconn, vuid);
197                         }
198                 }
199         }
200 }
201
202 /****************************************************************************
203  Reply to a session setup command.
204  conn POINTER CAN BE NULL HERE !
205 ****************************************************************************/
206
207 static void reply_sesssetup_and_X_spnego(struct smb_request *req)
208 {
209         const uint8 *p;
210         DATA_BLOB blob1;
211         size_t bufrem;
212         char *tmp;
213         const char *native_os;
214         const char *native_lanman;
215         const char *primary_domain;
216         const char *p2;
217         uint16 data_blob_len = SVAL(req->vwv+7, 0);
218         enum remote_arch_types ra_type = get_remote_arch();
219         int vuid = req->vuid;
220         user_struct *vuser = NULL;
221         NTSTATUS status = NT_STATUS_OK;
222         struct smbd_server_connection *sconn = req->sconn;
223         DATA_BLOB chal;
224
225         DEBUG(3,("Doing spnego session setup\n"));
226
227         if (global_client_caps == 0) {
228                 global_client_caps = IVAL(req->vwv+10, 0);
229
230                 if (!(global_client_caps & CAP_STATUS32)) {
231                         remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
232                 }
233
234         }
235
236         p = req->buf;
237
238         if (data_blob_len == 0) {
239                 /* an invalid request */
240                 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
241                 return;
242         }
243
244         bufrem = smbreq_bufrem(req, p);
245         /* pull the spnego blob */
246         blob1 = data_blob(p, MIN(bufrem, data_blob_len));
247
248 #if 0
249         file_save("negotiate.dat", blob1.data, blob1.length);
250 #endif
251
252         p2 = (const char *)req->buf + blob1.length;
253
254         p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
255                                      STR_TERMINATE);
256         native_os = tmp ? tmp : "";
257
258         p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
259                                      STR_TERMINATE);
260         native_lanman = tmp ? tmp : "";
261
262         p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
263                                      STR_TERMINATE);
264         primary_domain = tmp ? tmp : "";
265
266         DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
267                 native_os, native_lanman, primary_domain));
268
269         if ( ra_type == RA_WIN2K ) {
270                 /* Vista sets neither the OS or lanman strings */
271
272                 if ( !strlen(native_os) && !strlen(native_lanman) )
273                         set_remote_arch(RA_VISTA);
274
275                 /* Windows 2003 doesn't set the native lanman string,
276                    but does set primary domain which is a bug I think */
277
278                 if ( !strlen(native_lanman) ) {
279                         ra_lanman_string( primary_domain );
280                 } else {
281                         ra_lanman_string( native_lanman );
282                 }
283         } else if ( ra_type == RA_VISTA ) {
284                 if ( strncmp(native_os, "Mac OS X", 8) == 0 ) {
285                         set_remote_arch(RA_OSX);
286                 }
287         }
288
289         /* Do we have a valid vuid now ? */
290         if (!is_partial_auth_vuid(sconn, vuid)) {
291                 /* No, start a new authentication setup. */
292                 vuid = register_initial_vuid(sconn);
293                 if (vuid == UID_FIELD_INVALID) {
294                         data_blob_free(&blob1);
295                         reply_nterror(req, nt_status_squash(
296                                               NT_STATUS_INVALID_PARAMETER));
297                         return;
298                 }
299         }
300
301         vuser = get_partial_auth_user_struct(sconn, vuid);
302         /* This MUST be valid. */
303         if (!vuser) {
304                 smb_panic("reply_sesssetup_and_X_spnego: invalid vuid.");
305         }
306
307         if (!vuser->gensec_security) {
308                 status = auth_generic_prepare(vuser, sconn->remote_address,
309                                               &vuser->gensec_security);
310                 if (!NT_STATUS_IS_OK(status)) {
311                         /* Kill the intermediate vuid */
312                         invalidate_vuid(sconn, vuid);
313                         data_blob_free(&blob1);
314                         reply_nterror(req, nt_status_squash(status));
315                         return;
316                 }
317
318                 gensec_want_feature(vuser->gensec_security, GENSEC_FEATURE_SESSION_KEY);
319                 gensec_want_feature(vuser->gensec_security, GENSEC_FEATURE_UNIX_TOKEN);
320
321                 if (sconn->use_gensec_hook) {
322                         status = gensec_start_mech_by_oid(vuser->gensec_security, GENSEC_OID_SPNEGO);
323                 } else {
324                         status = gensec_start_mech_by_oid(vuser->gensec_security, GENSEC_OID_NTLMSSP);
325                 }
326                 if (!NT_STATUS_IS_OK(status)) {
327                         /* Kill the intermediate vuid */
328                         invalidate_vuid(sconn, vuid);
329                         data_blob_free(&blob1);
330                         reply_nterror(req, nt_status_squash(status));
331                         return;
332                 }
333         }
334
335         status = gensec_update(vuser->gensec_security,
336                                talloc_tos(), NULL,
337                                blob1, &chal);
338
339         data_blob_free(&blob1);
340
341         reply_spnego_generic(req, vuid,
342                              &vuser->gensec_security,
343                              &chal, status);
344         data_blob_free(&chal);
345         return;
346 }
347
348 /****************************************************************************
349  On new VC == 0, shutdown *all* old connections and users.
350  It seems that only NT4.x does this. At W2K and above (XP etc.).
351  a new session setup with VC==0 is ignored.
352 ****************************************************************************/
353
354 struct shutdown_state {
355         const char *ip;
356         struct messaging_context *msg_ctx;
357 };
358
359 static int shutdown_other_smbds(const struct connections_key *key,
360                                 const struct connections_data *crec,
361                                 void *private_data)
362 {
363         struct shutdown_state *state = (struct shutdown_state *)private_data;
364
365         DEBUG(10, ("shutdown_other_smbds: %s, %s\n",
366                    server_id_str(talloc_tos(), &crec->pid), crec->addr));
367
368         if (!process_exists(crec->pid)) {
369                 DEBUG(10, ("process does not exist\n"));
370                 return 0;
371         }
372
373         if (procid_is_me(&crec->pid)) {
374                 DEBUG(10, ("It's me\n"));
375                 return 0;
376         }
377
378         if (strcmp(state->ip, crec->addr) != 0) {
379                 DEBUG(10, ("%s does not match %s\n", state->ip, crec->addr));
380                 return 0;
381         }
382
383         DEBUG(1, ("shutdown_other_smbds: shutting down pid %u "
384                   "(IP %s)\n", (unsigned int)procid_to_pid(&crec->pid),
385                   state->ip));
386
387         messaging_send(state->msg_ctx, crec->pid, MSG_SHUTDOWN,
388                        &data_blob_null);
389         return 0;
390 }
391
392 static void setup_new_vc_session(struct smbd_server_connection *sconn)
393 {
394         DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x "
395                 "compatible we would close all old resources.\n"));
396 #if 0
397         conn_close_all();
398         invalidate_all_vuids();
399 #endif
400         if (lp_reset_on_zero_vc()) {
401                 char *addr;
402                 struct shutdown_state state;
403
404                 addr = tsocket_address_inet_addr_string(
405                         sconn->remote_address, talloc_tos());
406                 if (addr == NULL) {
407                         return;
408                 }
409                 state.ip = addr;
410                 state.msg_ctx = sconn->msg_ctx;
411                 connections_forall_read(shutdown_other_smbds, &state);
412                 TALLOC_FREE(addr);
413         }
414 }
415
416 /****************************************************************************
417  Reply to a session setup command.
418 ****************************************************************************/
419
420 void reply_sesssetup_and_X(struct smb_request *req)
421 {
422         int sess_vuid;
423         int smb_bufsize;
424         DATA_BLOB lm_resp;
425         DATA_BLOB nt_resp;
426         DATA_BLOB plaintext_password;
427         char *tmp;
428         const char *user;
429         fstring sub_user; /* Sanitised username for substituion */
430         const char *domain;
431         const char *native_os;
432         const char *native_lanman;
433         const char *primary_domain;
434         struct auth_usersupplied_info *user_info = NULL;
435         struct auth_serversupplied_info *server_info = NULL;
436         struct auth_session_info *session_info = NULL;
437         uint16 smb_flag2 = req->flags2;
438
439         NTSTATUS nt_status;
440         struct smbd_server_connection *sconn = req->sconn;
441
442         bool doencrypt = sconn->smb1.negprot.encrypted_passwords;
443         bool signing_allowed = false;
444         bool signing_mandatory = false;
445
446         START_PROFILE(SMBsesssetupX);
447
448         ZERO_STRUCT(lm_resp);
449         ZERO_STRUCT(nt_resp);
450         ZERO_STRUCT(plaintext_password);
451
452         DEBUG(3,("wct=%d flg2=0x%x\n", req->wct, req->flags2));
453
454         if (req->flags2 & FLAGS2_SMB_SECURITY_SIGNATURES) {
455                 signing_allowed = true;
456         }
457         if (req->flags2 & FLAGS2_SMB_SECURITY_SIGNATURES_REQUIRED) {
458                 signing_mandatory = true;
459         }
460
461         /*
462          * We can call srv_set_signing_negotiated() each time.
463          * It finds out when it needs to turn into a noop
464          * itself.
465          */
466         srv_set_signing_negotiated(req->sconn,
467                                    signing_allowed,
468                                    signing_mandatory);
469
470         /* a SPNEGO session setup has 12 command words, whereas a normal
471            NT1 session setup has 13. See the cifs spec. */
472         if (req->wct == 12 &&
473             (req->flags2 & FLAGS2_EXTENDED_SECURITY)) {
474
475                 if (!sconn->smb1.negprot.spnego) {
476                         DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt "
477                                  "at SPNEGO session setup when it was not "
478                                  "negotiated.\n"));
479                         reply_nterror(req, nt_status_squash(
480                                               NT_STATUS_LOGON_FAILURE));
481                         END_PROFILE(SMBsesssetupX);
482                         return;
483                 }
484
485                 if (SVAL(req->vwv+4, 0) == 0) {
486                         setup_new_vc_session(req->sconn);
487                 }
488
489                 reply_sesssetup_and_X_spnego(req);
490                 END_PROFILE(SMBsesssetupX);
491                 return;
492         }
493
494         smb_bufsize = SVAL(req->vwv+2, 0);
495
496         if (get_Protocol() < PROTOCOL_NT1) {
497                 uint16 passlen1 = SVAL(req->vwv+7, 0);
498
499                 /* Never do NT status codes with protocols before NT1 as we
500                  * don't get client caps. */
501                 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
502
503                 if ((passlen1 > MAX_PASS_LEN) || (passlen1 > req->buflen)) {
504                         reply_nterror(req, nt_status_squash(
505                                               NT_STATUS_INVALID_PARAMETER));
506                         END_PROFILE(SMBsesssetupX);
507                         return;
508                 }
509
510                 if (doencrypt) {
511                         lm_resp = data_blob(req->buf, passlen1);
512                 } else {
513                         plaintext_password = data_blob(req->buf, passlen1+1);
514                         /* Ensure null termination */
515                         plaintext_password.data[passlen1] = 0;
516                 }
517
518                 srvstr_pull_req_talloc(talloc_tos(), req, &tmp,
519                                        req->buf + passlen1, STR_TERMINATE);
520                 user = tmp ? tmp : "";
521
522                 domain = "";
523
524         } else {
525                 uint16 passlen1 = SVAL(req->vwv+7, 0);
526                 uint16 passlen2 = SVAL(req->vwv+8, 0);
527                 enum remote_arch_types ra_type = get_remote_arch();
528                 const uint8_t *p = req->buf;
529                 const uint8_t *save_p = req->buf;
530                 uint16 byte_count;
531
532
533                 if(global_client_caps == 0) {
534                         global_client_caps = IVAL(req->vwv+11, 0);
535
536                         if (!(global_client_caps & CAP_STATUS32)) {
537                                 remove_from_common_flags2(
538                                                 FLAGS2_32_BIT_ERROR_CODES);
539                         }
540
541                         /* client_caps is used as final determination if
542                          * client is NT or Win95. This is needed to return
543                          * the correct error codes in some circumstances.
544                         */
545
546                         if(ra_type == RA_WINNT || ra_type == RA_WIN2K ||
547                                         ra_type == RA_WIN95) {
548                                 if(!(global_client_caps & (CAP_NT_SMBS|
549                                                         CAP_STATUS32))) {
550                                         set_remote_arch( RA_WIN95);
551                                 }
552                         }
553                 }
554
555                 if (!doencrypt) {
556                         /* both Win95 and WinNT stuff up the password
557                          * lengths for non-encrypting systems. Uggh.
558
559                            if passlen1==24 its a win95 system, and its setting
560                            the password length incorrectly. Luckily it still
561                            works with the default code because Win95 will null
562                            terminate the password anyway
563
564                            if passlen1>0 and passlen2>0 then maybe its a NT box
565                            and its setting passlen2 to some random value which
566                            really stuffs things up. we need to fix that one.  */
567
568                         if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 &&
569                                         passlen2 != 1) {
570                                 passlen2 = 0;
571                         }
572                 }
573
574                 /* check for nasty tricks */
575                 if (passlen1 > MAX_PASS_LEN
576                     || passlen1 > smbreq_bufrem(req, p)) {
577                         reply_nterror(req, nt_status_squash(
578                                               NT_STATUS_INVALID_PARAMETER));
579                         END_PROFILE(SMBsesssetupX);
580                         return;
581                 }
582
583                 if (passlen2 > MAX_PASS_LEN
584                     || passlen2 > smbreq_bufrem(req, p+passlen1)) {
585                         reply_nterror(req, nt_status_squash(
586                                               NT_STATUS_INVALID_PARAMETER));
587                         END_PROFILE(SMBsesssetupX);
588                         return;
589                 }
590
591                 /* Save the lanman2 password and the NT md4 password. */
592
593                 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
594                         doencrypt = False;
595                 }
596
597                 if (doencrypt) {
598                         lm_resp = data_blob(p, passlen1);
599                         nt_resp = data_blob(p+passlen1, passlen2);
600                 } else if (lp_security() != SEC_SHARE) {
601                         /*
602                          * In share level we should ignore any passwords, so
603                          * only read them if we're not.
604                          */
605                         char *pass = NULL;
606                         bool unic= smb_flag2 & FLAGS2_UNICODE_STRINGS;
607
608                         if (unic && (passlen2 == 0) && passlen1) {
609                                 /* Only a ascii plaintext password was sent. */
610                                 (void)srvstr_pull_talloc(talloc_tos(),
611                                                         req->inbuf,
612                                                         req->flags2,
613                                                         &pass,
614                                                         req->buf,
615                                                         passlen1,
616                                                         STR_TERMINATE|STR_ASCII);
617                         } else {
618                                 (void)srvstr_pull_talloc(talloc_tos(),
619                                                         req->inbuf,
620                                                         req->flags2,
621                                                         &pass,
622                                                         req->buf,
623                                                         unic ? passlen2 : passlen1,
624                                                         STR_TERMINATE);
625                         }
626                         if (!pass) {
627                                 reply_nterror(req, nt_status_squash(
628                                               NT_STATUS_INVALID_PARAMETER));
629                                 END_PROFILE(SMBsesssetupX);
630                                 return;
631                         }
632                         plaintext_password = data_blob(pass, strlen(pass)+1);
633                 }
634
635                 p += passlen1 + passlen2;
636
637                 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
638                                             STR_TERMINATE);
639                 user = tmp ? tmp : "";
640
641                 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
642                                             STR_TERMINATE);
643                 domain = tmp ? tmp : "";
644
645                 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
646                                             STR_TERMINATE);
647                 native_os = tmp ? tmp : "";
648
649                 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
650                                             STR_TERMINATE);
651                 native_lanman = tmp ? tmp : "";
652
653                 /* not documented or decoded by Ethereal but there is one more
654                  * string in the extra bytes which is the same as the
655                  * PrimaryDomain when using extended security.  Windows NT 4
656                  * and 2003 use this string to store the native lanman string.
657                  * Windows 9x does not include a string here at all so we have
658                  * to check if we have any extra bytes left */
659
660                 byte_count = SVAL(req->vwv+13, 0);
661                 if ( PTR_DIFF(p, save_p) < byte_count) {
662                         p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
663                                                     STR_TERMINATE);
664                         primary_domain = tmp ? tmp : "";
665                 } else {
666                         primary_domain = talloc_strdup(talloc_tos(), "null");
667                 }
668
669                 DEBUG(3,("Domain=[%s]  NativeOS=[%s] NativeLanMan=[%s] "
670                         "PrimaryDomain=[%s]\n",
671                         domain, native_os, native_lanman, primary_domain));
672
673                 if ( ra_type == RA_WIN2K ) {
674                         if ( strlen(native_lanman) == 0 )
675                                 ra_lanman_string( primary_domain );
676                         else
677                                 ra_lanman_string( native_lanman );
678                 }
679
680         }
681
682         if (SVAL(req->vwv+4, 0) == 0) {
683                 setup_new_vc_session(req->sconn);
684         }
685
686         DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n",
687                                 domain, user, get_remote_machine_name()));
688
689         if (*user) {
690                 if (sconn->smb1.negprot.spnego) {
691
692                         /* This has to be here, because this is a perfectly
693                          * valid behaviour for guest logons :-( */
694
695                         DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt "
696                                 "at 'normal' session setup after "
697                                 "negotiating spnego.\n"));
698                         reply_nterror(req, nt_status_squash(
699                                               NT_STATUS_LOGON_FAILURE));
700                         END_PROFILE(SMBsesssetupX);
701                         return;
702                 }
703                 fstrcpy(sub_user, user);
704         } else {
705                 fstrcpy(sub_user, "");
706         }
707
708         sub_set_smb_name(sub_user);
709
710         reload_services(sconn, conn_snum_used, true);
711
712         if (lp_security() == SEC_SHARE) {
713                 char *sub_user_mapped = NULL;
714                 /* In share level we should ignore any passwords */
715
716                 data_blob_free(&lm_resp);
717                 data_blob_free(&nt_resp);
718                 data_blob_clear_free(&plaintext_password);
719
720                 (void)map_username(talloc_tos(), sub_user, &sub_user_mapped);
721                 if (!sub_user_mapped) {
722                         reply_nterror(req, NT_STATUS_NO_MEMORY);
723                         END_PROFILE(SMBsesssetupX);
724                         return;
725                 }
726                 fstrcpy(sub_user, sub_user_mapped);
727                 add_session_user(sconn, sub_user);
728                 add_session_workgroup(sconn, domain);
729                 /* Then force it to null for the benfit of the code below */
730                 user = "";
731         }
732
733         if (!*user) {
734
735                 nt_status = check_guest_password(sconn->remote_address, &server_info);
736
737         } else if (doencrypt) {
738                 struct auth_context *negprot_auth_context = NULL;
739                 negprot_auth_context = sconn->smb1.negprot.auth_context;
740                 if (!negprot_auth_context) {
741                         DEBUG(0, ("reply_sesssetup_and_X:  Attempted encrypted "
742                                 "session setup without negprot denied!\n"));
743                         reply_nterror(req, nt_status_squash(
744                                               NT_STATUS_LOGON_FAILURE));
745                         END_PROFILE(SMBsesssetupX);
746                         return;
747                 }
748                 nt_status = make_user_info_for_reply_enc(&user_info, user,
749                                                 domain,
750                                                 sconn->remote_address,
751                                                 lm_resp, nt_resp);
752                 if (NT_STATUS_IS_OK(nt_status)) {
753                         nt_status = negprot_auth_context->check_ntlm_password(
754                                         negprot_auth_context,
755                                         user_info,
756                                         &server_info);
757                 }
758         } else {
759                 struct auth_context *plaintext_auth_context = NULL;
760
761                 nt_status = make_auth_context_subsystem(
762                         talloc_tos(), &plaintext_auth_context);
763
764                 if (NT_STATUS_IS_OK(nt_status)) {
765                         uint8_t chal[8];
766
767                         plaintext_auth_context->get_ntlm_challenge(
768                                         plaintext_auth_context, chal);
769
770                         if (!make_user_info_for_reply(&user_info,
771                                                       user, domain,
772                                                       sconn->remote_address,
773                                                       chal,
774                                                       plaintext_password)) {
775                                 nt_status = NT_STATUS_NO_MEMORY;
776                         }
777
778                         if (NT_STATUS_IS_OK(nt_status)) {
779                                 nt_status = plaintext_auth_context->check_ntlm_password(
780                                                 plaintext_auth_context,
781                                                 user_info,
782                                                 &server_info);
783
784                                 TALLOC_FREE(plaintext_auth_context);
785                         }
786                 }
787         }
788
789         free_user_info(&user_info);
790
791         if (!NT_STATUS_IS_OK(nt_status)) {
792                 nt_status = do_map_to_guest_server_info(nt_status, &server_info,
793                                                         user, domain);
794         }
795
796         if (!NT_STATUS_IS_OK(nt_status)) {
797                 data_blob_free(&nt_resp);
798                 data_blob_free(&lm_resp);
799                 data_blob_clear_free(&plaintext_password);
800                 reply_nterror(req, nt_status_squash(nt_status));
801                 END_PROFILE(SMBsesssetupX);
802                 return;
803         }
804
805         nt_status = create_local_token(req, server_info, NULL, sub_user, &session_info);
806         TALLOC_FREE(server_info);
807
808         if (!NT_STATUS_IS_OK(nt_status)) {
809                 DEBUG(10, ("create_local_token failed: %s\n",
810                            nt_errstr(nt_status)));
811                 data_blob_free(&nt_resp);
812                 data_blob_free(&lm_resp);
813                 data_blob_clear_free(&plaintext_password);
814                 reply_nterror(req, nt_status_squash(nt_status));
815                 END_PROFILE(SMBsesssetupX);
816                 return;
817         }
818
819         data_blob_clear_free(&plaintext_password);
820
821         /* it's ok - setup a reply */
822         reply_outbuf(req, 3, 0);
823         if (get_Protocol() >= PROTOCOL_NT1) {
824                 push_signature(&req->outbuf);
825                 /* perhaps grab OS version here?? */
826         }
827
828         if (security_session_user_level(session_info, NULL) < SECURITY_USER) {
829                 SSVAL(req->outbuf,smb_vwv2,1);
830         }
831
832         /* register the name and uid as being validated, so further connections
833            to a uid can get through without a password, on the same VC */
834
835         if (lp_security() == SEC_SHARE) {
836                 sess_vuid = UID_FIELD_INVALID;
837                 TALLOC_FREE(session_info);
838         } else {
839                 /* Ignore the initial vuid. */
840                 sess_vuid = register_initial_vuid(sconn);
841                 if (sess_vuid == UID_FIELD_INVALID) {
842                         data_blob_free(&nt_resp);
843                         data_blob_free(&lm_resp);
844                         reply_nterror(req, nt_status_squash(
845                                               NT_STATUS_LOGON_FAILURE));
846                         END_PROFILE(SMBsesssetupX);
847                         return;
848                 }
849                 /* register_existing_vuid keeps the session_info */
850                 sess_vuid = register_existing_vuid(sconn, sess_vuid,
851                                         session_info,
852                                         nt_resp.data ? nt_resp : lm_resp);
853                 if (sess_vuid == UID_FIELD_INVALID) {
854                         data_blob_free(&nt_resp);
855                         data_blob_free(&lm_resp);
856                         reply_nterror(req, nt_status_squash(
857                                               NT_STATUS_LOGON_FAILURE));
858                         END_PROFILE(SMBsesssetupX);
859                         return;
860                 }
861
862                 /* current_user_info is changed on new vuid */
863                 reload_services(sconn, conn_snum_used, true);
864         }
865
866         data_blob_free(&nt_resp);
867         data_blob_free(&lm_resp);
868
869         SSVAL(req->outbuf,smb_uid,sess_vuid);
870         SSVAL(discard_const_p(char, req->inbuf),smb_uid,sess_vuid);
871         req->vuid = sess_vuid;
872
873         if (!sconn->smb1.sessions.done_sesssetup) {
874                 sconn->smb1.sessions.max_send =
875                         MIN(sconn->smb1.sessions.max_send,smb_bufsize);
876         }
877         sconn->smb1.sessions.done_sesssetup = true;
878
879         END_PROFILE(SMBsesssetupX);
880         chain_reply(req);
881         return;
882 }