A nice *big* change to the fundemental way we do things.
[ira/wip.git] / source3 / smbd / sesssetup.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 3.0
4    handle SMBsessionsetup
5    Copyright (C) Andrew Tridgell 1998-2001
6    Copyright (C) Andrew Bartlett      2001
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24
25 uint32 global_client_caps = 0;
26 static struct auth_context *ntlmssp_auth_context = NULL;
27
28 /*
29   on a logon error possibly map the error to success if "map to guest"
30   is set approriately
31 */
32 static NTSTATUS do_map_to_guest(NTSTATUS status, auth_serversupplied_info **server_info,
33                                 const char *user, const char *domain)
34 {
35         if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
36                 if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) || 
37                     (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) {
38                         DEBUG(3,("No such user %s [%s] - using guest account\n",
39                                  user, domain));
40                         make_server_info_guest(server_info);
41                         status = NT_STATUS_OK;
42                 }
43         }
44
45         if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
46                 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) {
47                         DEBUG(3,("Registered username %s for guest access\n",user));
48                         make_server_info_guest(server_info);
49                         status = NT_STATUS_OK;
50                 }
51         }
52
53         return status;
54 }
55
56
57 /****************************************************************************
58  Add the standard 'Samba' signature to the end of the session setup.
59 ****************************************************************************/
60 static void add_signature(char *outbuf) 
61 {
62         char *p;
63         p = smb_buf(outbuf);
64         p += srvstr_push(outbuf, p, "Unix", -1, STR_TERMINATE);
65         p += srvstr_push(outbuf, p, "Samba", -1, STR_TERMINATE);
66         p += srvstr_push(outbuf, p, lp_workgroup(), -1, STR_TERMINATE);
67         set_message_end(outbuf,p);
68 }
69
70 /****************************************************************************
71  Do a 'guest' logon, getting back the 
72 ****************************************************************************/
73 static NTSTATUS check_guest_password(auth_serversupplied_info **server_info) 
74 {
75         struct auth_context *auth_context;
76         auth_usersupplied_info *user_info = NULL;
77         
78         NTSTATUS nt_status;
79         unsigned char chal[8];
80
81         ZERO_STRUCT(chal);
82
83         DEBUG(3,("Got anonymous request\n"));
84
85         if (!NT_STATUS_IS_OK(nt_status = make_auth_context_fixed(&auth_context, chal))) {
86                 return nt_status;
87         }
88
89         if (!make_user_info_guest(&user_info)) {
90                 (auth_context->free)(&auth_context);
91                 return NT_STATUS_NO_MEMORY;
92         }
93         
94         nt_status = auth_context->check_ntlm_password(auth_context, user_info, server_info);
95         (auth_context->free)(&auth_context);
96         free_user_info(&user_info);
97         return nt_status;
98 }
99
100
101 #ifdef HAVE_KRB5
102 /****************************************************************************
103 reply to a session setup spnego negotiate packet for kerberos
104 ****************************************************************************/
105 static int reply_spnego_kerberos(connection_struct *conn, 
106                                  char *inbuf, char *outbuf,
107                                  int length, int bufsize,
108                                  DATA_BLOB *secblob)
109 {
110         DATA_BLOB ticket;
111         char *client, *p;
112         const struct passwd *pw;
113         char *user;
114         int sess_vuid;
115         NTSTATUS ret;
116         DATA_BLOB auth_data;
117         auth_serversupplied_info *server_info = NULL;
118         ADS_STRUCT *ads;
119
120         if (!spnego_parse_krb5_wrap(*secblob, &ticket)) {
121                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
122         }
123
124         ads = ads_init(NULL, NULL, NULL, NULL);
125
126         ret = ads_verify_ticket(ads, &ticket, &client, &auth_data);
127         if (!NT_STATUS_IS_OK(ret)) {
128                 DEBUG(1,("Failed to verify incoming ticket!\n"));       
129                 ads_destroy(&ads);
130                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
131         }
132
133         DEBUG(3,("Ticket name is [%s]\n", client));
134
135         p = strchr_m(client, '@');
136         if (!p) {
137                 DEBUG(3,("Doesn't look like a valid principal\n"));
138                 ads_destroy(&ads);
139                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
140         }
141
142         *p = 0;
143         if (strcasecmp(p+1, ads->realm) != 0) {
144                 DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1));
145                 if (!lp_allow_trusted_domains()) {
146                         return ERROR_NT(NT_STATUS_LOGON_FAILURE);
147                 }
148                 /* this gives a fully qualified user name (ie. with full realm).
149                    that leads to very long usernames, but what else can we do? */
150                 asprintf(&user, "%s%s%s", p+1, lp_winbind_separator(), client);
151         } else {
152                 user = strdup(client);
153         }
154         ads_destroy(&ads);
155
156         /* the password is good - let them in */
157         pw = smb_getpwnam(user,False);
158         if (!pw && !strstr(user, lp_winbind_separator())) {
159                 char *user2;
160                 /* try it with a winbind domain prefix */
161                 asprintf(&user2, "%s%s%s", lp_workgroup(), lp_winbind_separator(), user);
162                 pw = smb_getpwnam(user2,False);
163                 if (pw) {
164                         free(user);
165                         user = user2;
166                 }
167         }
168
169         if (!pw) {
170                 DEBUG(1,("Username %s is invalid on this system\n",user));
171                 return ERROR_NT(NT_STATUS_NO_SUCH_USER);
172         }
173
174         if (!make_server_info_pw(&server_info,pw)) {
175                 DEBUG(1,("make_server_info_from_pw failed!\n"));
176                 return ERROR_NT(NT_STATUS_NO_MEMORY);
177         }
178         
179         sess_vuid = register_vuid(server_info, user);
180
181         free(user);
182         free_server_info(&server_info);
183
184         if (sess_vuid == -1) {
185                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
186         }
187
188         set_message(outbuf,4,0,True);
189         SSVAL(outbuf, smb_vwv3, 0);
190         add_signature(outbuf);
191  
192         SSVAL(outbuf,smb_uid,sess_vuid);
193         SSVAL(inbuf,smb_uid,sess_vuid);
194         
195         return chain_reply(inbuf,outbuf,length,bufsize);
196 }
197 #endif
198
199
200 /****************************************************************************
201 send a security blob via a session setup reply
202 ****************************************************************************/
203 static BOOL reply_sesssetup_blob(connection_struct *conn, char *outbuf,
204                                  DATA_BLOB blob)
205 {
206         char *p;
207
208         set_message(outbuf,4,0,True);
209
210         /* we set NT_STATUS_MORE_PROCESSING_REQUIRED to tell the other end
211            that we aren't finished yet */
212
213         SIVAL(outbuf, smb_rcls, NT_STATUS_V(NT_STATUS_MORE_PROCESSING_REQUIRED));
214         SSVAL(outbuf, smb_vwv0, 0xFF); /* no chaining possible */
215         SSVAL(outbuf, smb_vwv3, blob.length);
216         p = smb_buf(outbuf);
217         memcpy(p, blob.data, blob.length);
218         p += blob.length;
219         p += srvstr_push(outbuf, p, "Unix", -1, STR_TERMINATE);
220         p += srvstr_push(outbuf, p, "Samba", -1, STR_TERMINATE);
221         p += srvstr_push(outbuf, p, lp_workgroup(), -1, STR_TERMINATE);
222         set_message_end(outbuf,p);
223         
224         return send_smb(smbd_server_fd(),outbuf);
225 }
226
227 /****************************************************************************
228 reply to a session setup spnego negotiate packet
229 ****************************************************************************/
230 static int reply_spnego_negotiate(connection_struct *conn, 
231                                   char *inbuf,
232                                   char *outbuf,
233                                   int length, int bufsize,
234                                   DATA_BLOB blob1)
235 {
236         char *OIDs[ASN1_MAX_OIDS];
237         DATA_BLOB secblob;
238         int i;
239         uint32 ntlmssp_command, neg_flags;
240         DATA_BLOB sess_key, chal, spnego_chal;
241         const uint8 *cryptkey;
242         BOOL got_kerberos = False;
243         NTSTATUS nt_status;
244
245         /* parse out the OIDs and the first sec blob */
246         if (!parse_negTokenTarg(blob1, OIDs, &secblob)) {
247                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
248         }
249         
250         for (i=0;OIDs[i];i++) {
251                 DEBUG(3,("Got OID %s\n", OIDs[i]));
252                 if (strcmp(OID_KERBEROS5, OIDs[i]) == 0 ||
253                     strcmp(OID_KERBEROS5_OLD, OIDs[i]) == 0) {
254                         got_kerberos = True;
255                 }
256                 free(OIDs[i]);
257         }
258         DEBUG(3,("Got secblob of size %d\n", secblob.length));
259
260 #ifdef HAVE_KRB5
261         if (got_kerberos) {
262                 int ret = reply_spnego_kerberos(conn, inbuf, outbuf, 
263                                                 length, bufsize, &secblob);
264                 data_blob_free(&secblob);
265                 return ret;
266         }
267 #endif
268
269         /* parse the NTLMSSP packet */
270 #if 0
271         file_save("secblob.dat", secblob.data, secblob.length);
272 #endif
273
274         if (!msrpc_parse(&secblob, "CddB",
275                          "NTLMSSP",
276                          &ntlmssp_command,
277                          &neg_flags,
278                          &sess_key)) {
279                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
280         }
281
282         data_blob_free(&secblob);
283         data_blob_free(&sess_key);
284
285         if (ntlmssp_command != NTLMSSP_NEGOTIATE) {
286                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
287         }
288
289         DEBUG(3,("Got neg_flags=%08x\n", neg_flags));
290
291         if (ntlmssp_auth_context) {
292                 (ntlmssp_auth_context->free)(&ntlmssp_auth_context);
293         }
294
295         if (!NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&ntlmssp_auth_context))) {
296                 return ERROR_NT(nt_status);
297         }
298
299         cryptkey = ntlmssp_auth_context->get_ntlm_challenge(ntlmssp_auth_context);
300
301         /* Give them the challenge. For now, ignore neg_flags and just
302            return the flags we want. Obviously this is not correct */
303         
304         neg_flags = NTLMSSP_NEGOTIATE_UNICODE | 
305                 NTLMSSP_NEGOTIATE_LM_KEY | 
306                 NTLMSSP_NEGOTIATE_NTLM;
307
308         msrpc_gen(&chal, "Cddddbdddd",
309                   "NTLMSSP", 
310                   NTLMSSP_CHALLENGE,
311                   0,
312                   0x30, /* ?? */
313                   neg_flags,
314                   cryptkey, 8,
315                   0, 0, 0,
316                   0x3000); /* ?? */
317
318         if (!spnego_gen_challenge(&spnego_chal, &chal, &chal)) {
319                 DEBUG(3,("Failed to generate challenge\n"));
320                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
321         }
322
323         /* now tell the client to send the auth packet */
324         reply_sesssetup_blob(conn, outbuf, spnego_chal);
325
326         data_blob_free(&chal);
327         data_blob_free(&spnego_chal);
328
329         /* and tell smbd that we have already replied to this packet */
330         return -1;
331 }
332
333         
334 /****************************************************************************
335 reply to a session setup spnego auth packet
336 ****************************************************************************/
337 static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
338                              int length, int bufsize,
339                              DATA_BLOB blob1)
340 {
341         DATA_BLOB auth;
342         char *workgroup = NULL, *user = NULL, *machine = NULL;
343         DATA_BLOB lmhash, nthash, sess_key;
344         DATA_BLOB plaintext_password = data_blob(NULL, 0);
345         uint32 ntlmssp_command, neg_flags;
346         NTSTATUS nt_status;
347         int sess_vuid;
348         BOOL as_guest;
349         uint32 auth_flags = AUTH_FLAG_NONE;
350
351         auth_usersupplied_info *user_info = NULL;
352         auth_serversupplied_info *server_info = NULL;
353
354         if (!spnego_parse_auth(blob1, &auth)) {
355 #if 0
356                 file_save("auth.dat", blob1.data, blob1.length);
357 #endif
358                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
359         }
360
361         /* now the NTLMSSP encoded auth hashes */
362         if (!msrpc_parse(&auth, "CdBBUUUBd", 
363                          "NTLMSSP", 
364                          &ntlmssp_command, 
365                          &lmhash,
366                          &nthash,
367                          &workgroup, 
368                          &user, 
369                          &machine,
370                          &sess_key,
371                          &neg_flags)) {
372                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
373         }
374
375         data_blob_free(&auth);
376         data_blob_free(&sess_key);
377         
378         DEBUG(3,("Got user=[%s] workgroup=[%s] machine=[%s] len1=%d len2=%d\n",
379                  user, workgroup, machine, lmhash.length, nthash.length));
380
381 #if 0
382         file_save("nthash1.dat", nthash.data, nthash.length);
383         file_save("lmhash1.dat", lmhash.data, lmhash.length);
384 #endif
385
386         if (lmhash.length) {
387                 auth_flags |= AUTH_FLAG_LM_RESP;
388         }
389
390         if (nthash.length == 24) {
391                 auth_flags |= AUTH_FLAG_NTLM_RESP;
392         } else if (nthash.length > 24) {
393                 auth_flags |= AUTH_FLAG_NTLMv2_RESP;
394         }
395
396         if (!make_user_info_map(&user_info, 
397                                 user, workgroup, 
398                                 machine, 
399                                 lmhash, nthash,
400                                 plaintext_password, 
401                                 auth_flags, True)) {
402                 return ERROR_NT(NT_STATUS_NO_MEMORY);
403         }
404
405         nt_status = ntlmssp_auth_context->check_ntlm_password(ntlmssp_auth_context, user_info, &server_info); 
406
407         if (!NT_STATUS_IS_OK(nt_status)) {
408                 nt_status = do_map_to_guest(nt_status, &server_info, user, workgroup);
409         }
410
411         SAFE_FREE(workgroup);
412         SAFE_FREE(machine);
413                         
414         (ntlmssp_auth_context->free)(&ntlmssp_auth_context);
415
416         free_user_info(&user_info);
417         
418         data_blob_free(&lmhash);
419         
420         data_blob_free(&nthash);
421
422         if (!NT_STATUS_IS_OK(nt_status)) {
423                 SAFE_FREE(user);
424                 return ERROR_NT(nt_status_squash(nt_status));
425         }
426
427         as_guest = server_info->guest;
428
429         sess_vuid = register_vuid(server_info, user);
430         free_server_info(&server_info);
431
432         SAFE_FREE(user);
433   
434         if (sess_vuid == -1) {
435                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
436         }
437
438         set_message(outbuf,4,0,True);
439         SSVAL(outbuf, smb_vwv3, 0);
440
441         if (as_guest) {
442                 SSVAL(outbuf,smb_vwv2,1);
443         }
444
445         add_signature(outbuf);
446  
447         SSVAL(outbuf,smb_uid,sess_vuid);
448         SSVAL(inbuf,smb_uid,sess_vuid);
449         
450         return chain_reply(inbuf,outbuf,length,bufsize);
451 }
452
453
454 /****************************************************************************
455 reply to a session setup spnego anonymous packet
456 ****************************************************************************/
457 static int reply_spnego_anonymous(connection_struct *conn, char *inbuf, char *outbuf,
458                                   int length, int bufsize)
459 {
460         int sess_vuid;
461         auth_serversupplied_info *server_info = NULL;
462         NTSTATUS nt_status;
463
464         nt_status = check_guest_password(&server_info);
465
466         if (!NT_STATUS_IS_OK(nt_status)) {
467                 return ERROR_NT(nt_status_squash(nt_status));
468         }
469
470         sess_vuid = register_vuid(server_info, lp_guestaccount());
471
472         free_server_info(&server_info);
473   
474         if (sess_vuid == -1) {
475                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
476         }
477
478         set_message(outbuf,4,0,True);
479         SSVAL(outbuf, smb_vwv3, 0);
480         add_signature(outbuf);
481  
482         SSVAL(outbuf,smb_uid,sess_vuid);
483         SSVAL(inbuf,smb_uid,sess_vuid);
484         
485         return chain_reply(inbuf,outbuf,length,bufsize);
486 }
487
488
489 /****************************************************************************
490 reply to a session setup command
491 ****************************************************************************/
492 static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,char *outbuf,
493                                         int length,int bufsize)
494 {
495         uint8 *p;
496         DATA_BLOB blob1;
497         int ret;
498
499         DEBUG(3,("Doing spnego session setup\n"));
500
501         if (global_client_caps == 0) {
502                 global_client_caps = IVAL(inbuf,smb_vwv10);
503         }
504                 
505         p = (uint8 *)smb_buf(inbuf);
506
507         if (SVAL(inbuf, smb_vwv7) == 0) {
508                 /* an anonymous request */
509                 return reply_spnego_anonymous(conn, inbuf, outbuf, length, bufsize);
510         }
511
512         /* pull the spnego blob */
513         blob1 = data_blob(p, SVAL(inbuf, smb_vwv7));
514
515 #if 0
516         file_save("negotiate.dat", blob1.data, blob1.length);
517 #endif
518
519         if (blob1.data[0] == ASN1_APPLICATION(0)) {
520                 /* its a negTokenTarg packet */
521                 ret = reply_spnego_negotiate(conn, inbuf, outbuf, length, bufsize, blob1);
522                 data_blob_free(&blob1);
523                 return ret;
524         }
525
526         if (blob1.data[0] == ASN1_CONTEXT(1)) {
527                 /* its a auth packet */
528                 ret = reply_spnego_auth(conn, inbuf, outbuf, length, bufsize, blob1);
529                 data_blob_free(&blob1);
530                 return ret;
531         }
532
533         /* what sort of packet is this? */
534         DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
535
536         data_blob_free(&blob1);
537
538         return ERROR_NT(NT_STATUS_LOGON_FAILURE);
539 }
540
541
542 /****************************************************************************
543 reply to a session setup command
544 ****************************************************************************/
545 int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
546                           int length,int bufsize)
547 {
548         int sess_vuid;
549         int   smb_bufsize;    
550         DATA_BLOB lm_resp;
551         DATA_BLOB nt_resp;
552         DATA_BLOB plaintext_password;
553         pstring user;
554         pstring sub_user; /* Sainitised username for substituion */
555         fstring domain;
556         fstring native_os;
557         fstring native_lanman;
558         static BOOL done_sesssetup = False;
559         extern BOOL global_encrypted_passwords_negotiated;
560         extern BOOL global_spnego_negotiated;
561         extern int Protocol;
562         extern fstring remote_machine;
563         extern userdom_struct current_user_info;
564         extern int max_send;
565
566         auth_usersupplied_info *user_info = NULL;
567         extern struct auth_context *negprot_global_auth_context;
568         auth_serversupplied_info *server_info = NULL;
569
570         NTSTATUS nt_status;
571
572         BOOL doencrypt = global_encrypted_passwords_negotiated;
573
574         START_PROFILE(SMBsesssetupX);
575
576         ZERO_STRUCT(lm_resp);
577         ZERO_STRUCT(nt_resp);
578         ZERO_STRUCT(plaintext_password);
579
580         DEBUG(3,("wct=%d flg2=0x%x\n", CVAL(inbuf, smb_wct), SVAL(inbuf, smb_flg2)));
581
582         /* a SPNEGO session setup has 12 command words, whereas a normal
583            NT1 session setup has 13. See the cifs spec. */
584         if (CVAL(inbuf, smb_wct) == 12 &&
585             (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
586                 if (!global_spnego_negotiated) {
587                         DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt at SPNEGO session setup when it was not negoitiated.\n"));
588                         return ERROR_NT(NT_STATUS_UNSUCCESSFUL);
589                 }
590
591                 return reply_sesssetup_and_X_spnego(conn, inbuf, outbuf, length, bufsize);
592         }
593
594         smb_bufsize = SVAL(inbuf,smb_vwv2);
595
596         if (Protocol < PROTOCOL_NT1) {
597                 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
598                 if (passlen1 > MAX_PASS_LEN) {
599                         return ERROR_DOS(ERRDOS,ERRbuftoosmall);
600                 }
601
602                 if (doencrypt) {
603                         lm_resp = data_blob(smb_buf(inbuf), passlen1);
604                 } else {
605                         plaintext_password = data_blob(smb_buf(inbuf), passlen1+1);
606                         /* Ensure null termination */
607                         plaintext_password.data[passlen1] = 0;
608                 }
609
610                 srvstr_pull(inbuf, user, smb_buf(inbuf)+passlen1, sizeof(user), -1, STR_TERMINATE);
611                 *domain = 0;
612   
613         } else {
614                 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
615                 uint16 passlen2 = SVAL(inbuf,smb_vwv8);
616                 enum remote_arch_types ra_type = get_remote_arch();
617                 char *p = smb_buf(inbuf);    
618
619                 if(global_client_caps == 0)
620                         global_client_caps = IVAL(inbuf,smb_vwv11);
621                 
622                 /* client_caps is used as final determination if client is NT or Win95. 
623                    This is needed to return the correct error codes in some
624                    circumstances.
625                 */
626                 
627                 if(ra_type == RA_WINNT || ra_type == RA_WIN2K || ra_type == RA_WIN95) {
628                         if(!(global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))) {
629                                 set_remote_arch( RA_WIN95);
630                         }
631                 }
632                 
633                 if (passlen1 > MAX_PASS_LEN) {
634                         return ERROR_DOS(ERRDOS,ERRbuftoosmall);
635                 }
636
637                 passlen1 = MIN(passlen1, MAX_PASS_LEN);
638                 passlen2 = MIN(passlen2, MAX_PASS_LEN);
639
640                 if (!doencrypt) {
641                         /* both Win95 and WinNT stuff up the password lengths for
642                            non-encrypting systems. Uggh. 
643                            
644                            if passlen1==24 its a win95 system, and its setting the
645                            password length incorrectly. Luckily it still works with the
646                            default code because Win95 will null terminate the password
647                            anyway 
648                            
649                            if passlen1>0 and passlen2>0 then maybe its a NT box and its
650                            setting passlen2 to some random value which really stuffs
651                            things up. we need to fix that one.  */
652                         
653                         if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 && passlen2 != 1)
654                                 passlen2 = 0;
655                 }
656                 
657                 /* Save the lanman2 password and the NT md4 password. */
658                 
659                 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
660                         doencrypt = False;
661                 }
662                 
663                 if (doencrypt) {
664                         lm_resp = data_blob(p, passlen1);
665                         nt_resp = data_blob(p+passlen1, passlen2);
666                 } else {
667                         plaintext_password = data_blob(p, passlen1+1);
668                         /* Ensure null termination */
669                         plaintext_password.data[passlen1] = 0;
670                 }
671                 
672                 p += passlen1 + passlen2;
673                 p += srvstr_pull(inbuf, user, p, sizeof(user), -1,
674                                  STR_TERMINATE);
675                 p += srvstr_pull(inbuf, domain, p, sizeof(domain), 
676                                  -1, STR_TERMINATE);
677                 p += srvstr_pull(inbuf, native_os, p, sizeof(native_os), 
678                                  -1, STR_TERMINATE);
679                 p += srvstr_pull(inbuf, native_lanman, p, sizeof(native_lanman),
680                                  -1, STR_TERMINATE);
681                 DEBUG(3,("Domain=[%s]  NativeOS=[%s] NativeLanMan=[%s]\n",
682                          domain,native_os,native_lanman));
683         }
684         
685         /* don't allow for weird usernames or domains */
686         alpha_strcpy(user, user, ". _-$", sizeof(user));
687         alpha_strcpy(domain, domain, ". _-", sizeof(domain));
688         if (strstr(user, "..") || strstr(domain,"..")) {
689                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
690         }
691
692         DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n", domain, user, remote_machine));
693
694         if (*user) {
695                 if (global_spnego_negotiated) {
696                         
697                         /* This has to be here, becouse this is a perfectly valid behaviour for guest logons :-( */
698                         
699                         DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt at 'normal' session setup after negotiating spnego.\n"));
700                         return ERROR_NT(NT_STATUS_UNSUCCESSFUL);
701                 }
702                 pstrcpy(sub_user, user);
703         } else {
704                 pstrcpy(sub_user, lp_guestaccount());
705         }
706
707         pstrcpy(current_user_info.smb_name,sub_user);
708
709         reload_services(True);
710         
711         if (lp_security() == SEC_SHARE) {
712                 /* in share level we should ignore any passwords */
713
714                 data_blob_free(&lm_resp);
715                 data_blob_free(&nt_resp);
716                 data_blob_clear_free(&plaintext_password);
717
718                 map_username(sub_user);
719                 add_session_user(sub_user);
720                 /* Then force it to null for the benfit of the code below */
721                 *user = 0;
722         }
723         
724         if (!*user) {
725
726                 nt_status = check_guest_password(&server_info);
727
728         } else if (doencrypt) {
729                 if (!make_user_info_for_reply_enc(&user_info, 
730                                                   user, domain, 
731                                                   lm_resp, nt_resp)) {
732                         nt_status = NT_STATUS_NO_MEMORY;
733                 } else {
734                         nt_status = negprot_global_auth_context->check_ntlm_password(negprot_global_auth_context, 
735                                                                                      user_info, 
736                                                                                      &server_info);
737                 }
738         } else {
739                 struct auth_context *plaintext_auth_context = NULL;
740                 const uint8 *chal;
741                 if (NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&plaintext_auth_context))) {
742                         chal = plaintext_auth_context->get_ntlm_challenge(plaintext_auth_context);
743                         
744                         if (!make_user_info_for_reply(&user_info, 
745                                                       user, domain, chal,
746                                                       plaintext_password)) {
747                                 nt_status = NT_STATUS_NO_MEMORY;
748                         }
749                 
750                         if (NT_STATUS_IS_OK(nt_status)) {
751                                 nt_status = plaintext_auth_context->check_ntlm_password(plaintext_auth_context, 
752                                                                                         user_info, 
753                                                                                         &server_info); 
754                                 
755                                 (plaintext_auth_context->free)(&plaintext_auth_context);
756                         }
757                 }
758         }
759
760         free_user_info(&user_info);
761         
762         data_blob_free(&lm_resp);
763         data_blob_free(&nt_resp);
764         data_blob_clear_free(&plaintext_password);
765         
766         if (!NT_STATUS_IS_OK(nt_status)) {
767                 nt_status = do_map_to_guest(nt_status, &server_info, user, domain);
768         }
769         
770         if (!NT_STATUS_IS_OK(nt_status)) {
771                 return ERROR_NT(nt_status_squash(nt_status));
772         }
773         
774         /* it's ok - setup a reply */
775         if (Protocol < PROTOCOL_NT1) {
776                 set_message(outbuf,3,0,True);
777         } else {
778                 set_message(outbuf,3,0,True);
779                 add_signature(outbuf);
780                 /* perhaps grab OS version here?? */
781         }
782         
783         if (server_info->guest) {
784                 SSVAL(outbuf,smb_vwv2,1);
785         }
786
787         /* register the name and uid as being validated, so further connections
788            to a uid can get through without a password, on the same VC */
789
790         sess_vuid = register_vuid(server_info, sub_user);
791
792         free_server_info(&server_info);
793   
794         if (sess_vuid == -1) {
795                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
796         }
797
798  
799         SSVAL(outbuf,smb_uid,sess_vuid);
800         SSVAL(inbuf,smb_uid,sess_vuid);
801         
802         if (!done_sesssetup)
803                 max_send = MIN(max_send,smb_bufsize);
804         
805         done_sesssetup = True;
806         
807         END_PROFILE(SMBsesssetupX);
808         return chain_reply(inbuf,outbuf,length,bufsize);
809 }