Doxygen janitor: add note that strequal is in fact case-insensitive.
[samba.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        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
26 uint32 global_client_caps = 0;
27
28 static struct auth_ntlmssp_state *global_ntlmssp_state;
29
30 /*
31   on a logon error possibly map the error to success if "map to guest"
32   is set approriately
33 */
34 static NTSTATUS do_map_to_guest(NTSTATUS status, auth_serversupplied_info **server_info,
35                                 const char *user, const char *domain)
36 {
37         if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
38                 if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) || 
39                     (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) {
40                         DEBUG(3,("No such user %s [%s] - using guest account\n",
41                                  user, domain));
42                         make_server_info_guest(server_info);
43                         status = NT_STATUS_OK;
44                 }
45         }
46
47         if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
48                 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) {
49                         DEBUG(3,("Registered username %s for guest access\n",user));
50                         make_server_info_guest(server_info);
51                         status = NT_STATUS_OK;
52                 }
53         }
54
55         return status;
56 }
57
58
59 /****************************************************************************
60  Add the standard 'Samba' signature to the end of the session setup.
61 ****************************************************************************/
62 static void add_signature(char *outbuf) 
63 {
64         char *p;
65         p = smb_buf(outbuf);
66         p += srvstr_push(outbuf, p, "Unix", -1, STR_TERMINATE);
67         p += srvstr_push(outbuf, p, "Samba", -1, STR_TERMINATE);
68         p += srvstr_push(outbuf, p, lp_workgroup(), -1, STR_TERMINATE);
69         set_message_end(outbuf,p);
70 }
71
72 /****************************************************************************
73 send a security blob via a session setup reply
74 ****************************************************************************/
75 static BOOL reply_sesssetup_blob(connection_struct *conn, char *outbuf,
76                                  DATA_BLOB blob, NTSTATUS nt_status)
77 {
78         char *p;
79
80         set_message(outbuf,4,0,True);
81
82         /* we set NT_STATUS_MORE_PROCESSING_REQUIRED to tell the other end
83            that we aren't finished yet */
84
85         nt_status = nt_status_squash(nt_status);
86         SIVAL(outbuf, smb_rcls, NT_STATUS_V(nt_status));
87         SSVAL(outbuf, smb_vwv0, 0xFF); /* no chaining possible */
88         SSVAL(outbuf, smb_vwv3, blob.length);
89         p = smb_buf(outbuf);
90
91         /* should we cap this? */
92         memcpy(p, blob.data, blob.length);
93         p += blob.length;
94
95         p += srvstr_push(outbuf, p, "Unix", -1, STR_TERMINATE);
96         p += srvstr_push(outbuf, p, "Samba", -1, STR_TERMINATE);
97         p += srvstr_push(outbuf, p, lp_workgroup(), -1, STR_TERMINATE);
98         set_message_end(outbuf,p);
99
100         return send_smb(smbd_server_fd(),outbuf);
101 }
102
103 /****************************************************************************
104  Do a 'guest' logon, getting back the 
105 ****************************************************************************/
106 static NTSTATUS check_guest_password(auth_serversupplied_info **server_info) 
107 {
108         struct auth_context *auth_context;
109         auth_usersupplied_info *user_info = NULL;
110         
111         NTSTATUS nt_status;
112         unsigned char chal[8];
113
114         ZERO_STRUCT(chal);
115
116         DEBUG(3,("Got anonymous request\n"));
117
118         if (!NT_STATUS_IS_OK(nt_status = make_auth_context_fixed(&auth_context, chal))) {
119                 return nt_status;
120         }
121
122         if (!make_user_info_guest(&user_info)) {
123                 (auth_context->free)(&auth_context);
124                 return NT_STATUS_NO_MEMORY;
125         }
126         
127         nt_status = auth_context->check_ntlm_password(auth_context, user_info, server_info);
128         (auth_context->free)(&auth_context);
129         free_user_info(&user_info);
130         return nt_status;
131 }
132
133
134 #ifdef HAVE_KRB5
135 /****************************************************************************
136 reply to a session setup spnego negotiate packet for kerberos
137 ****************************************************************************/
138 static int reply_spnego_kerberos(connection_struct *conn, 
139                                  char *inbuf, char *outbuf,
140                                  int length, int bufsize,
141                                  DATA_BLOB *secblob)
142 {
143         DATA_BLOB ticket;
144         char *client, *p;
145         const struct passwd *pw;
146         char *user;
147         int sess_vuid;
148         NTSTATUS ret;
149         DATA_BLOB auth_data;
150         DATA_BLOB ap_rep, ap_rep_wrapped, response;
151         auth_serversupplied_info *server_info = NULL;
152         ADS_STRUCT *ads;
153         uint8 session_key[16];
154         uint8 tok_id[2];
155         BOOL foreign = False;
156
157         if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) {
158                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
159         }
160
161         ads = ads_init_simple();
162
163         if (!ads) {
164                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
165         }
166
167         ads->auth.realm = strdup(lp_realm());
168
169         ret = ads_verify_ticket(ads, &ticket, &client, &auth_data, &ap_rep, session_key);
170         if (!NT_STATUS_IS_OK(ret)) {
171                 DEBUG(1,("Failed to verify incoming ticket!\n"));       
172                 ads_destroy(&ads);
173                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
174         }
175
176         data_blob_free(&auth_data);
177
178         DEBUG(3,("Ticket name is [%s]\n", client));
179
180         p = strchr_m(client, '@');
181         if (!p) {
182                 DEBUG(3,("Doesn't look like a valid principal\n"));
183                 ads_destroy(&ads);
184                 data_blob_free(&ap_rep);
185                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
186         }
187
188         *p = 0;
189         if (strcasecmp(p+1, ads->auth.realm) != 0) {
190                 DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1));
191                 if (!lp_allow_trusted_domains()) {
192                         data_blob_free(&ap_rep);
193                         return ERROR_NT(NT_STATUS_LOGON_FAILURE);
194                 }
195                 foreign = True;
196         }
197
198         /* this gives a fully qualified user name (ie. with full realm).
199            that leads to very long usernames, but what else can we do? */
200         asprintf(&user, "%s%s%s", p+1, lp_winbind_separator(), client);
201         
202         pw = Get_Pwnam(user);
203         if (!pw && !foreign) {
204                 pw = Get_Pwnam(client);
205                 SAFE_FREE(user);
206                 user = smb_xstrdup(client);
207         }
208
209         ads_destroy(&ads);
210
211         /* setup the string used by %U */
212         sub_set_smb_name(user);
213
214         reload_services(True);
215
216         if (!pw) {
217                 DEBUG(1,("Username %s is invalid on this system\n",user));
218                 data_blob_free(&ap_rep);
219                 return ERROR_NT(NT_STATUS_NO_SUCH_USER);
220         }
221
222         if (!NT_STATUS_IS_OK(ret = make_server_info_pw(&server_info,pw))) {
223                 DEBUG(1,("make_server_info_from_pw failed!\n"));
224                 data_blob_free(&ap_rep);
225                 return ERROR_NT(ret);
226         }
227
228         /* Copy out the session key from the AP_REQ. */
229         memcpy(server_info->session_key, session_key, sizeof(session_key));
230
231         /* register_vuid keeps the server info */
232         sess_vuid = register_vuid(server_info, user);
233
234         free(user);
235
236         if (sess_vuid == -1) {
237                 ret = NT_STATUS_LOGON_FAILURE;
238         } else {
239                 set_message(outbuf,4,0,True);
240                 SSVAL(outbuf, smb_vwv3, 0);
241                         
242                 if (server_info->guest) {
243                         SSVAL(outbuf,smb_vwv2,1);
244                 }
245                 
246                 SSVAL(outbuf, smb_uid, sess_vuid);
247         }
248
249         /* wrap that up in a nice GSS-API wrapping */
250         if (NT_STATUS_IS_OK(ret)) {
251                 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep, TOK_ID_KRB_AP_REP);
252         } else {
253                 ap_rep_wrapped = data_blob(NULL, 0);
254         }
255         response = spnego_gen_auth_response(&ap_rep_wrapped, ret, OID_KERBEROS5_OLD);
256         reply_sesssetup_blob(conn, outbuf, response, ret);
257
258         data_blob_free(&ap_rep);
259         data_blob_free(&ap_rep_wrapped);
260         data_blob_free(&response);
261
262         return -1; /* already replied */
263 }
264 #endif
265
266
267 /****************************************************************************
268  send a session setup reply, wrapped in SPNEGO.
269  get vuid and check first.
270  end the NTLMSSP exchange context if we are OK/complete fail
271 ***************************************************************************/
272 static BOOL reply_spnego_ntlmssp(connection_struct *conn, char *outbuf,
273                                  AUTH_NTLMSSP_STATE **auth_ntlmssp_state,
274                                  DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status) 
275 {
276         BOOL ret;
277         DATA_BLOB response;
278         struct auth_serversupplied_info *server_info;
279         server_info = (*auth_ntlmssp_state)->server_info;
280
281         if (!NT_STATUS_IS_OK(nt_status)) {
282                 nt_status = do_map_to_guest(nt_status, 
283                                             &server_info, 
284                                             (*auth_ntlmssp_state)->ntlmssp_state->user, 
285                                             (*auth_ntlmssp_state)->ntlmssp_state->domain);
286         }
287
288         if (NT_STATUS_IS_OK(nt_status)) {
289                 int sess_vuid;
290                 /* register_vuid keeps the server info */
291                 sess_vuid = register_vuid(server_info, (*auth_ntlmssp_state)->ntlmssp_state->user);
292                 (*auth_ntlmssp_state)->server_info = NULL;
293
294                 if (sess_vuid == -1) {
295                         nt_status = NT_STATUS_LOGON_FAILURE;
296                 } else {
297                         
298                         set_message(outbuf,4,0,True);
299                         SSVAL(outbuf, smb_vwv3, 0);
300                         
301                         if (server_info->guest) {
302                                 SSVAL(outbuf,smb_vwv2,1);
303                         }
304                         
305                         SSVAL(outbuf,smb_uid,sess_vuid);
306                 }
307         }
308
309         response = spnego_gen_auth_response(ntlmssp_blob, nt_status, OID_NTLMSSP);
310         ret = reply_sesssetup_blob(conn, outbuf, response, nt_status);
311         data_blob_free(&response);
312
313         if (!ret || !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
314                 auth_ntlmssp_end(auth_ntlmssp_state);
315         }
316
317         return ret;
318 }
319
320 /****************************************************************************
321 reply to a session setup spnego negotiate packet
322 ****************************************************************************/
323 static int reply_spnego_negotiate(connection_struct *conn, 
324                                   char *inbuf,
325                                   char *outbuf,
326                                   int length, int bufsize,
327                                   DATA_BLOB blob1)
328 {
329         char *OIDs[ASN1_MAX_OIDS];
330         DATA_BLOB secblob;
331         int i;
332         DATA_BLOB chal;
333         BOOL got_kerberos = False;
334         NTSTATUS nt_status;
335
336         /* parse out the OIDs and the first sec blob */
337         if (!parse_negTokenTarg(blob1, OIDs, &secblob)) {
338                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
339         }
340         
341         for (i=0;OIDs[i];i++) {
342                 DEBUG(3,("Got OID %s\n", OIDs[i]));
343                 if (strcmp(OID_KERBEROS5, OIDs[i]) == 0 ||
344                     strcmp(OID_KERBEROS5_OLD, OIDs[i]) == 0) {
345                         got_kerberos = True;
346                 }
347                 free(OIDs[i]);
348         }
349         DEBUG(3,("Got secblob of size %d\n", secblob.length));
350
351 #ifdef HAVE_KRB5
352         if (got_kerberos && (SEC_ADS == lp_security())) {
353                 int ret = reply_spnego_kerberos(conn, inbuf, outbuf, 
354                                                 length, bufsize, &secblob);
355                 data_blob_free(&secblob);
356                 return ret;
357         }
358 #endif
359
360         if (global_ntlmssp_state) {
361                 auth_ntlmssp_end(&global_ntlmssp_state);
362         }
363
364         nt_status = auth_ntlmssp_start(&global_ntlmssp_state);
365         if (!NT_STATUS_IS_OK(nt_status)) {
366                 return ERROR_NT(nt_status);
367         }
368
369         nt_status = auth_ntlmssp_update(global_ntlmssp_state, 
370                                         secblob, &chal);
371
372         data_blob_free(&secblob);
373
374         reply_spnego_ntlmssp(conn, outbuf, &global_ntlmssp_state,
375                              &chal, nt_status);
376                 
377         data_blob_free(&chal);
378
379         /* already replied */
380         return -1;
381 }
382
383         
384 /****************************************************************************
385 reply to a session setup spnego auth packet
386 ****************************************************************************/
387 static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
388                              int length, int bufsize,
389                              DATA_BLOB blob1)
390 {
391         DATA_BLOB auth, auth_reply;
392         NTSTATUS nt_status;
393
394         if (!spnego_parse_auth(blob1, &auth)) {
395 #if 0
396                 file_save("auth.dat", blob1.data, blob1.length);
397 #endif
398                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
399         }
400
401         nt_status = auth_ntlmssp_update(global_ntlmssp_state, 
402                                           auth, &auth_reply);
403
404         data_blob_free(&auth);
405
406         reply_spnego_ntlmssp(conn, outbuf, &global_ntlmssp_state,
407                              &auth_reply, nt_status);
408                 
409         data_blob_free(&auth_reply);
410
411         /* and tell smbd that we have already replied to this packet */
412         return -1;
413 }
414
415
416 /****************************************************************************
417 reply to a session setup command
418 ****************************************************************************/
419 static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,
420                                         char *outbuf,
421                                         int length,int bufsize)
422 {
423         uint8 *p;
424         DATA_BLOB blob1;
425         int ret;
426         size_t bufrem;
427
428         DEBUG(3,("Doing spnego session setup\n"));
429
430         if (global_client_caps == 0) {
431                 global_client_caps = IVAL(inbuf,smb_vwv10);
432         }
433                 
434         p = (uint8 *)smb_buf(inbuf);
435
436         if (SVAL(inbuf, smb_vwv7) == 0) {
437                 /* an invalid request */
438                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
439         }
440
441         bufrem = smb_bufrem(inbuf, p);
442         /* pull the spnego blob */
443         blob1 = data_blob(p, MIN(bufrem, SVAL(inbuf, smb_vwv7)));
444
445 #if 0
446         file_save("negotiate.dat", blob1.data, blob1.length);
447 #endif
448
449         if (blob1.data[0] == ASN1_APPLICATION(0)) {
450                 /* its a negTokenTarg packet */
451                 ret = reply_spnego_negotiate(conn, inbuf, outbuf, length, bufsize, blob1);
452                 data_blob_free(&blob1);
453                 return ret;
454         }
455
456         if (blob1.data[0] == ASN1_CONTEXT(1)) {
457                 /* its a auth packet */
458                 ret = reply_spnego_auth(conn, inbuf, outbuf, length, bufsize, blob1);
459                 data_blob_free(&blob1);
460                 return ret;
461         }
462
463         /* what sort of packet is this? */
464         DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
465
466         data_blob_free(&blob1);
467
468         return ERROR_NT(NT_STATUS_LOGON_FAILURE);
469 }
470
471
472 /****************************************************************************
473 reply to a session setup command
474 ****************************************************************************/
475 int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
476                           int length,int bufsize)
477 {
478         int sess_vuid;
479         int   smb_bufsize;    
480         DATA_BLOB lm_resp;
481         DATA_BLOB nt_resp;
482         DATA_BLOB plaintext_password;
483         fstring user;
484         fstring sub_user; /* Sainitised username for substituion */
485         fstring domain;
486         fstring native_os;
487         fstring native_lanman;
488         static BOOL done_sesssetup = False;
489         extern BOOL global_encrypted_passwords_negotiated;
490         extern BOOL global_spnego_negotiated;
491         extern int Protocol;
492         extern int max_send;
493
494         auth_usersupplied_info *user_info = NULL;
495         extern struct auth_context *negprot_global_auth_context;
496         auth_serversupplied_info *server_info = NULL;
497
498         NTSTATUS nt_status;
499
500         BOOL doencrypt = global_encrypted_passwords_negotiated;
501         
502         START_PROFILE(SMBsesssetupX);
503
504         ZERO_STRUCT(lm_resp);
505         ZERO_STRUCT(nt_resp);
506         ZERO_STRUCT(plaintext_password);
507
508         DEBUG(3,("wct=%d flg2=0x%x\n", CVAL(inbuf, smb_wct), SVAL(inbuf, smb_flg2)));
509
510         /* a SPNEGO session setup has 12 command words, whereas a normal
511            NT1 session setup has 13. See the cifs spec. */
512         if (CVAL(inbuf, smb_wct) == 12 &&
513             (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
514                 if (!global_spnego_negotiated) {
515                         DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt at SPNEGO session setup when it was not negoitiated.\n"));
516                         return ERROR_NT(NT_STATUS_UNSUCCESSFUL);
517                 }
518
519                 return reply_sesssetup_and_X_spnego(conn, inbuf, outbuf, length, bufsize);
520         }
521
522         smb_bufsize = SVAL(inbuf,smb_vwv2);
523
524         if (Protocol < PROTOCOL_NT1) {
525                 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
526                 if ((passlen1 > MAX_PASS_LEN) || (passlen1 > smb_bufrem(inbuf, smb_buf(inbuf)))) {
527                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
528                 }
529
530                 if (doencrypt) {
531                         lm_resp = data_blob(smb_buf(inbuf), passlen1);
532                 } else {
533                         plaintext_password = data_blob(smb_buf(inbuf), passlen1+1);
534                         /* Ensure null termination */
535                         plaintext_password.data[passlen1] = 0;
536                 }
537
538                 srvstr_pull_buf(inbuf, user, smb_buf(inbuf)+passlen1, sizeof(user), STR_TERMINATE);
539                 *domain = 0;
540   
541         } else {
542                 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
543                 uint16 passlen2 = SVAL(inbuf,smb_vwv8);
544                 enum remote_arch_types ra_type = get_remote_arch();
545                 char *p = smb_buf(inbuf);    
546
547                 if(global_client_caps == 0)
548                         global_client_caps = IVAL(inbuf,smb_vwv11);
549                 
550                 /* client_caps is used as final determination if client is NT or Win95. 
551                    This is needed to return the correct error codes in some
552                    circumstances.
553                 */
554                 
555                 if(ra_type == RA_WINNT || ra_type == RA_WIN2K || ra_type == RA_WIN95) {
556                         if(!(global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))) {
557                                 set_remote_arch( RA_WIN95);
558                         }
559                 }
560
561                 if (!doencrypt) {
562                         /* both Win95 and WinNT stuff up the password lengths for
563                            non-encrypting systems. Uggh. 
564                            
565                            if passlen1==24 its a win95 system, and its setting the
566                            password length incorrectly. Luckily it still works with the
567                            default code because Win95 will null terminate the password
568                            anyway 
569                            
570                            if passlen1>0 and passlen2>0 then maybe its a NT box and its
571                            setting passlen2 to some random value which really stuffs
572                            things up. we need to fix that one.  */
573                         
574                         if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 && passlen2 != 1)
575                                 passlen2 = 0;
576                 }
577                 
578                 /* check for nasty tricks */
579                 if (passlen1 > MAX_PASS_LEN || passlen1 > smb_bufrem(inbuf, p)) {
580                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
581                 }
582
583                 if (passlen2 > MAX_PASS_LEN || passlen2 > smb_bufrem(inbuf, p+passlen1)) {
584                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
585                 }
586
587                 /* Save the lanman2 password and the NT md4 password. */
588                 
589                 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
590                         doencrypt = False;
591                 }
592
593                 if (doencrypt) {
594                         lm_resp = data_blob(p, passlen1);
595                         nt_resp = data_blob(p+passlen1, passlen2);
596                 } else {
597                         pstring pass;
598                         srvstr_pull(inbuf, pass, smb_buf(inbuf), 
599                                     sizeof(pass),  passlen1, STR_TERMINATE);
600                         plaintext_password = data_blob(pass, strlen(pass)+1);
601                 }
602                 
603                 p += passlen1 + passlen2;
604                 p += srvstr_pull_buf(inbuf, user, p, sizeof(user), STR_TERMINATE);
605                 p += srvstr_pull_buf(inbuf, domain, p, sizeof(domain), STR_TERMINATE);
606                 p += srvstr_pull_buf(inbuf, native_os, p, sizeof(native_os), STR_TERMINATE);
607                 p += srvstr_pull_buf(inbuf, native_lanman, p, sizeof(native_lanman), STR_TERMINATE);
608                 DEBUG(3,("Domain=[%s]  NativeOS=[%s] NativeLanMan=[%s]\n",
609                          domain,native_os,native_lanman));
610
611                 /* 
612                  * we distinguish between 2K and XP by the "Native Lan Manager" string
613                  *   WinXP => "Windows 2002 5.1"
614                  *   Win2k => "Windows 2000 5.0"
615                  *   NT4   => "Windows NT 4.0" 
616                  *   Win9x => "Windows 4.0"
617                  */
618                  
619                 if ( ra_type == RA_WIN2K ) {
620                         if ( 0 == strcmp( native_lanman, "Windows 2002 5.1" ) )
621                                 set_remote_arch( RA_WINXP );
622                 }
623                 
624
625         }
626         
627         DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n", domain, user, get_remote_machine_name()));
628
629         if (*user) {
630                 if (global_spnego_negotiated) {
631                         
632                         /* This has to be here, becouse this is a perfectly valid behaviour for guest logons :-( */
633                         
634                         DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt at 'normal' session setup after negotiating spnego.\n"));
635                         return ERROR_NT(NT_STATUS_UNSUCCESSFUL);
636                 }
637                 fstrcpy(sub_user, user);
638
639                 /* setup the string used by %U */
640                 sub_set_smb_name(user);
641         } else {
642                 fstrcpy(sub_user, lp_guestaccount());
643         }
644
645         sub_set_smb_name(sub_user);
646
647         reload_services(True);
648         
649         if (lp_security() == SEC_SHARE) {
650                 /* in share level we should ignore any passwords */
651
652                 data_blob_free(&lm_resp);
653                 data_blob_free(&nt_resp);
654                 data_blob_clear_free(&plaintext_password);
655
656                 map_username(sub_user);
657                 add_session_user(sub_user);
658                 /* Then force it to null for the benfit of the code below */
659                 *user = 0;
660         }
661         
662         if (!*user) {
663
664                 nt_status = check_guest_password(&server_info);
665
666         } else if (doencrypt) {
667                 if (!negprot_global_auth_context) {
668                         DEBUG(0, ("reply_sesssetup_and_X:  Attempted encrypted session setup without negprot denied!\n"));
669                         return ERROR_NT(NT_STATUS_LOGON_FAILURE);
670                 }
671                 nt_status = make_user_info_for_reply_enc(&user_info, user, domain,
672                                                          lm_resp, nt_resp);
673                 if (NT_STATUS_IS_OK(nt_status)) {
674                         nt_status = negprot_global_auth_context->check_ntlm_password(negprot_global_auth_context, 
675                                                                                      user_info, 
676                                                                                      &server_info);
677                 }
678         } else {
679                 struct auth_context *plaintext_auth_context = NULL;
680                 const uint8 *chal;
681                 if (NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&plaintext_auth_context))) {
682                         chal = plaintext_auth_context->get_ntlm_challenge(plaintext_auth_context);
683                         
684                         if (!make_user_info_for_reply(&user_info, 
685                                                       user, domain, chal,
686                                                       plaintext_password)) {
687                                 nt_status = NT_STATUS_NO_MEMORY;
688                         }
689                 
690                         if (NT_STATUS_IS_OK(nt_status)) {
691                                 nt_status = plaintext_auth_context->check_ntlm_password(plaintext_auth_context, 
692                                                                                         user_info, 
693                                                                                         &server_info); 
694                                 
695                                 (plaintext_auth_context->free)(&plaintext_auth_context);
696                         }
697                 }
698         }
699
700         free_user_info(&user_info);
701         
702         data_blob_free(&lm_resp);
703         data_blob_free(&nt_resp);
704         data_blob_clear_free(&plaintext_password);
705         
706         if (!NT_STATUS_IS_OK(nt_status)) {
707                 nt_status = do_map_to_guest(nt_status, &server_info, user, domain);
708         }
709         
710         if (!NT_STATUS_IS_OK(nt_status)) {
711                 return ERROR_NT(nt_status_squash(nt_status));
712         }
713         
714         /* it's ok - setup a reply */
715         set_message(outbuf,3,0,True);
716         if (Protocol >= PROTOCOL_NT1) {
717                 add_signature(outbuf);
718                 /* perhaps grab OS version here?? */
719         }
720         
721         if (server_info->guest) {
722                 SSVAL(outbuf,smb_vwv2,1);
723         }
724
725         /* register the name and uid as being validated, so further connections
726            to a uid can get through without a password, on the same VC */
727
728         /* register_vuid keeps the server info */
729         sess_vuid = register_vuid(server_info, sub_user);
730   
731         if (sess_vuid == -1) {
732                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
733         }
734
735         SSVAL(outbuf,smb_uid,sess_vuid);
736         SSVAL(inbuf,smb_uid,sess_vuid);
737         
738         if (!done_sesssetup)
739                 max_send = MIN(max_send,smb_bufsize);
740         
741         done_sesssetup = True;
742         
743         END_PROFILE(SMBsesssetupX);
744         return chain_reply(inbuf,outbuf,length,bufsize);
745 }