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