Get this code back to where it belongs...
[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
350         auth_usersupplied_info *user_info = NULL;
351         auth_serversupplied_info *server_info = NULL;
352
353         if (!spnego_parse_auth(blob1, &auth)) {
354 #if 0
355                 file_save("auth.dat", blob1.data, blob1.length);
356 #endif
357                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
358         }
359
360         /* now the NTLMSSP encoded auth hashes */
361         if (!msrpc_parse(&auth, "CdBBUUUBd", 
362                          "NTLMSSP", 
363                          &ntlmssp_command, 
364                          &lmhash,
365                          &nthash,
366                          &workgroup, 
367                          &user, 
368                          &machine,
369                          &sess_key,
370                          &neg_flags)) {
371                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
372         }
373
374         data_blob_free(&auth);
375         data_blob_free(&sess_key);
376         
377         DEBUG(3,("Got user=[%s] workgroup=[%s] machine=[%s] len1=%d len2=%d\n",
378                  user, workgroup, machine, lmhash.length, nthash.length));
379
380 #if 0
381         file_save("nthash1.dat", nthash.data, nthash.length);
382         file_save("lmhash1.dat", lmhash.data, lmhash.length);
383 #endif
384
385         if (!make_user_info_map(&user_info, 
386                                 user, workgroup, 
387                                 machine, 
388                                 lmhash, nthash,
389                                 plaintext_password, 
390                                 neg_flags, True)) {
391                 return ERROR_NT(NT_STATUS_NO_MEMORY);
392         }
393
394         nt_status = ntlmssp_auth_context->check_ntlm_password(ntlmssp_auth_context, user_info, &server_info); 
395
396         if (!NT_STATUS_IS_OK(nt_status)) {
397                 nt_status = do_map_to_guest(nt_status, &server_info, user, workgroup);
398         }
399
400         SAFE_FREE(workgroup);
401         SAFE_FREE(machine);
402                         
403         ntlmssp_auth_context->free(&ntlmssp_auth_context);
404
405         free_user_info(&user_info);
406         
407         data_blob_free(&lmhash);
408         
409         data_blob_free(&nthash);
410
411         if (!NT_STATUS_IS_OK(nt_status)) {
412                 SAFE_FREE(user);
413                 return ERROR_NT(nt_status_squash(nt_status));
414         }
415
416         as_guest = server_info->guest;
417
418         sess_vuid = register_vuid(server_info, user);
419         free_server_info(&server_info);
420
421         SAFE_FREE(user);
422   
423         if (sess_vuid == -1) {
424                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
425         }
426
427         set_message(outbuf,4,0,True);
428         SSVAL(outbuf, smb_vwv3, 0);
429
430         if (as_guest) {
431                 SSVAL(outbuf,smb_vwv2,1);
432         }
433
434         add_signature(outbuf);
435  
436         SSVAL(outbuf,smb_uid,sess_vuid);
437         SSVAL(inbuf,smb_uid,sess_vuid);
438         
439         return chain_reply(inbuf,outbuf,length,bufsize);
440 }
441
442
443 /****************************************************************************
444 reply to a session setup spnego anonymous packet
445 ****************************************************************************/
446 static int reply_spnego_anonymous(connection_struct *conn, char *inbuf, char *outbuf,
447                                   int length, int bufsize)
448 {
449         int sess_vuid;
450         auth_serversupplied_info *server_info = NULL;
451         NTSTATUS nt_status;
452
453         nt_status = check_guest_password(&server_info);
454
455         if (!NT_STATUS_IS_OK(nt_status)) {
456                 return ERROR_NT(nt_status_squash(nt_status));
457         }
458
459         sess_vuid = register_vuid(server_info, lp_guestaccount());
460
461         free_server_info(&server_info);
462   
463         if (sess_vuid == -1) {
464                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
465         }
466
467         set_message(outbuf,4,0,True);
468         SSVAL(outbuf, smb_vwv3, 0);
469         add_signature(outbuf);
470  
471         SSVAL(outbuf,smb_uid,sess_vuid);
472         SSVAL(inbuf,smb_uid,sess_vuid);
473         
474         return chain_reply(inbuf,outbuf,length,bufsize);
475 }
476
477
478 /****************************************************************************
479 reply to a session setup command
480 ****************************************************************************/
481 static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,char *outbuf,
482                                         int length,int bufsize)
483 {
484         uint8 *p;
485         DATA_BLOB blob1;
486         int ret;
487
488         DEBUG(3,("Doing spnego session setup\n"));
489
490         if (global_client_caps == 0) {
491                 global_client_caps = IVAL(inbuf,smb_vwv10);
492         }
493                 
494         p = (uint8 *)smb_buf(inbuf);
495
496         if (SVAL(inbuf, smb_vwv7) == 0) {
497                 /* an anonymous request */
498                 return reply_spnego_anonymous(conn, inbuf, outbuf, length, bufsize);
499         }
500
501         /* pull the spnego blob */
502         blob1 = data_blob(p, SVAL(inbuf, smb_vwv7));
503
504 #if 0
505         file_save("negotiate.dat", blob1.data, blob1.length);
506 #endif
507
508         if (blob1.data[0] == ASN1_APPLICATION(0)) {
509                 /* its a negTokenTarg packet */
510                 ret = reply_spnego_negotiate(conn, inbuf, outbuf, length, bufsize, blob1);
511                 data_blob_free(&blob1);
512                 return ret;
513         }
514
515         if (blob1.data[0] == ASN1_CONTEXT(1)) {
516                 /* its a auth packet */
517                 ret = reply_spnego_auth(conn, inbuf, outbuf, length, bufsize, blob1);
518                 data_blob_free(&blob1);
519                 return ret;
520         }
521
522         /* what sort of packet is this? */
523         DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
524
525         data_blob_free(&blob1);
526
527         return ERROR_NT(NT_STATUS_LOGON_FAILURE);
528 }
529
530
531 /****************************************************************************
532 reply to a session setup command
533 ****************************************************************************/
534 int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
535                           int length,int bufsize)
536 {
537         int sess_vuid;
538         int   smb_bufsize;    
539         DATA_BLOB lm_resp;
540         DATA_BLOB nt_resp;
541         DATA_BLOB plaintext_password;
542         pstring user;
543         pstring sub_user; /* Sainitised username for substituion */
544         fstring domain;
545         fstring native_os;
546         fstring native_lanman;
547         static BOOL done_sesssetup = False;
548         extern BOOL global_encrypted_passwords_negotiated;
549         extern BOOL global_spnego_negotiated;
550         extern int Protocol;
551         extern fstring remote_machine;
552         extern userdom_struct current_user_info;
553         extern int max_send;
554
555         auth_usersupplied_info *user_info = NULL;
556         extern struct auth_context *negprot_global_auth_context;
557         auth_serversupplied_info *server_info = NULL;
558
559         NTSTATUS nt_status;
560
561         BOOL doencrypt = global_encrypted_passwords_negotiated;
562
563         START_PROFILE(SMBsesssetupX);
564
565         ZERO_STRUCT(lm_resp);
566         ZERO_STRUCT(nt_resp);
567         ZERO_STRUCT(plaintext_password);
568
569         DEBUG(3,("wct=%d flg2=0x%x\n", CVAL(inbuf, smb_wct), SVAL(inbuf, smb_flg2)));
570
571         /* a SPNEGO session setup has 12 command words, whereas a normal
572            NT1 session setup has 13. See the cifs spec. */
573         if (CVAL(inbuf, smb_wct) == 12 &&
574             (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
575                 if (!global_spnego_negotiated) {
576                         DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt at SPNEGO session setup when it was not negoitiated.\n"));
577                         return ERROR_NT(NT_STATUS_UNSUCCESSFUL);
578                 }
579
580                 return reply_sesssetup_and_X_spnego(conn, inbuf, outbuf, length, bufsize);
581         }
582
583         smb_bufsize = SVAL(inbuf,smb_vwv2);
584
585         if (Protocol < PROTOCOL_NT1) {
586                 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
587                 if (passlen1 > MAX_PASS_LEN) {
588                         return ERROR_DOS(ERRDOS,ERRbuftoosmall);
589                 }
590
591                 if (doencrypt) {
592                         lm_resp = data_blob(smb_buf(inbuf), passlen1);
593                 } else {
594                         plaintext_password = data_blob(smb_buf(inbuf), passlen1+1);
595                         /* Ensure null termination */
596                         plaintext_password.data[passlen1] = 0;
597                 }
598
599                 srvstr_pull(inbuf, user, smb_buf(inbuf)+passlen1, sizeof(user), -1, STR_TERMINATE);
600                 *domain = 0;
601   
602         } else {
603                 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
604                 uint16 passlen2 = SVAL(inbuf,smb_vwv8);
605                 enum remote_arch_types ra_type = get_remote_arch();
606                 char *p = smb_buf(inbuf);    
607
608                 if(global_client_caps == 0)
609                         global_client_caps = IVAL(inbuf,smb_vwv11);
610                 
611                 /* client_caps is used as final determination if client is NT or Win95. 
612                    This is needed to return the correct error codes in some
613                    circumstances.
614                 */
615                 
616                 if(ra_type == RA_WINNT || ra_type == RA_WIN2K || ra_type == RA_WIN95) {
617                         if(!(global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))) {
618                                 set_remote_arch( RA_WIN95);
619                         }
620                 }
621                 
622                 if (passlen1 > MAX_PASS_LEN) {
623                         return ERROR_DOS(ERRDOS,ERRbuftoosmall);
624                 }
625
626                 passlen1 = MIN(passlen1, MAX_PASS_LEN);
627                 passlen2 = MIN(passlen2, MAX_PASS_LEN);
628
629                 if (!doencrypt) {
630                         /* both Win95 and WinNT stuff up the password lengths for
631                            non-encrypting systems. Uggh. 
632                            
633                            if passlen1==24 its a win95 system, and its setting the
634                            password length incorrectly. Luckily it still works with the
635                            default code because Win95 will null terminate the password
636                            anyway 
637                            
638                            if passlen1>0 and passlen2>0 then maybe its a NT box and its
639                            setting passlen2 to some random value which really stuffs
640                            things up. we need to fix that one.  */
641                         
642                         if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 && passlen2 != 1)
643                                 passlen2 = 0;
644                 }
645                 
646                 /* Save the lanman2 password and the NT md4 password. */
647                 
648                 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
649                         doencrypt = False;
650                 }
651                 
652                 if (doencrypt) {
653                         lm_resp = data_blob(p, passlen1);
654                         nt_resp = data_blob(p+passlen1, passlen2);
655                 } else {
656                         plaintext_password = data_blob(p, passlen1+1);
657                         /* Ensure null termination */
658                         plaintext_password.data[passlen1] = 0;
659                 }
660                 
661                 p += passlen1 + passlen2;
662                 p += srvstr_pull(inbuf, user, p, sizeof(user), -1,
663                                  STR_TERMINATE);
664                 p += srvstr_pull(inbuf, domain, p, sizeof(domain), 
665                                  -1, STR_TERMINATE);
666                 p += srvstr_pull(inbuf, native_os, p, sizeof(native_os), 
667                                  -1, STR_TERMINATE);
668                 p += srvstr_pull(inbuf, native_lanman, p, sizeof(native_lanman),
669                                  -1, STR_TERMINATE);
670                 DEBUG(3,("Domain=[%s]  NativeOS=[%s] NativeLanMan=[%s]\n",
671                          domain,native_os,native_lanman));
672         }
673         
674         /* don't allow for weird usernames or domains */
675         alpha_strcpy(user, user, ". _-$", sizeof(user));
676         alpha_strcpy(domain, domain, ". _-", sizeof(domain));
677         if (strstr(user, "..") || strstr(domain,"..")) {
678                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
679         }
680
681         DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n", domain, user, remote_machine));
682
683         if (*user) {
684                 if (global_spnego_negotiated) {
685                         
686                         /* This has to be here, becouse this is a perfectly valid behaviour for guest logons :-( */
687                         
688                         DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt at 'normal' session setup after negotiating spnego.\n"));
689                         return ERROR_NT(NT_STATUS_UNSUCCESSFUL);
690                 }
691                 pstrcpy(sub_user, user);
692         } else {
693                 pstrcpy(sub_user, lp_guestaccount());
694         }
695
696         pstrcpy(current_user_info.smb_name,sub_user);
697
698         reload_services(True);
699         
700         if (lp_security() == SEC_SHARE) {
701                 /* in share level we should ignore any passwords */
702
703                 data_blob_free(&lm_resp);
704                 data_blob_free(&nt_resp);
705                 data_blob_clear_free(&plaintext_password);
706
707                 map_username(sub_user);
708                 add_session_user(sub_user);
709                 /* Then force it to null for the benfit of the code below */
710                 *user = 0;
711         }
712         
713         if (!*user) {
714
715                 nt_status = check_guest_password(&server_info);
716
717         } else if (doencrypt) {
718                 if (!make_user_info_for_reply_enc(&user_info, 
719                                                   user, domain, 
720                                                   lm_resp, nt_resp)) {
721                         nt_status = NT_STATUS_NO_MEMORY;
722                 } else {
723                         nt_status = negprot_global_auth_context->check_ntlm_password(negprot_global_auth_context, 
724                                                                                      user_info, 
725                                                                                      &server_info);
726                 }
727         } else {
728                 struct auth_context *plaintext_auth_context = NULL;
729                 const uint8 *chal;
730                 if (NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&plaintext_auth_context))) {
731                         chal = plaintext_auth_context->get_ntlm_challenge(plaintext_auth_context);
732                         
733                         if (!make_user_info_for_reply(&user_info, 
734                                                       user, domain, chal,
735                                                       plaintext_password)) {
736                                 nt_status = NT_STATUS_NO_MEMORY;
737                         }
738                 
739                         if (NT_STATUS_IS_OK(nt_status)) {
740                                 nt_status = plaintext_auth_context->check_ntlm_password(plaintext_auth_context, 
741                                                                                         user_info, 
742                                                                                         &server_info); 
743                                 
744                                 plaintext_auth_context->free(&plaintext_auth_context);
745                         }
746                 }
747         }
748
749         free_user_info(&user_info);
750         
751         data_blob_free(&lm_resp);
752         data_blob_free(&nt_resp);
753         data_blob_clear_free(&plaintext_password);
754         
755         if (!NT_STATUS_IS_OK(nt_status)) {
756                 nt_status = do_map_to_guest(nt_status, &server_info, user, domain);
757         }
758         
759         if (!NT_STATUS_IS_OK(nt_status)) {
760                 return ERROR_NT(nt_status_squash(nt_status));
761         }
762         
763         /* it's ok - setup a reply */
764         if (Protocol < PROTOCOL_NT1) {
765                 set_message(outbuf,3,0,True);
766         } else {
767                 set_message(outbuf,3,0,True);
768                 add_signature(outbuf);
769                 /* perhaps grab OS version here?? */
770         }
771         
772         if (server_info->guest) {
773                 SSVAL(outbuf,smb_vwv2,1);
774         } else {
775                 const char *home_dir = pdb_get_homedir(server_info->sam_account);
776                 const char *username = pdb_get_username(server_info->sam_account);
777                 if ((home_dir && *home_dir)
778                     && (lp_servicenumber(username) < 0)) {
779                         add_home_service(username, home_dir);     
780                 }
781         }
782
783         /* register the name and uid as being validated, so further connections
784            to a uid can get through without a password, on the same VC */
785
786         sess_vuid = register_vuid(server_info, sub_user);
787
788         free_server_info(&server_info);
789   
790         if (sess_vuid == -1) {
791                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
792         }
793
794  
795         SSVAL(outbuf,smb_uid,sess_vuid);
796         SSVAL(inbuf,smb_uid,sess_vuid);
797         
798         if (!done_sesssetup)
799                 max_send = MIN(max_send,smb_bufsize);
800         
801         done_sesssetup = True;
802         
803         END_PROFILE(SMBsesssetupX);
804         return chain_reply(inbuf,outbuf,length,bufsize);
805 }