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