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