6a2bfc2d974be48ee018000fe8bda0d9d9374dc9
[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                 /* Save the lanman2 password and the NT md4 password. */
575                 
576                 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
577                         doencrypt = False;
578                 }
579                 
580                 if (doencrypt) {
581                         lm_resp = data_blob(p, passlen1);
582                         nt_resp = data_blob(p+passlen1, passlen2);
583                 } else {
584                         plaintext_password = data_blob(p, passlen1+1);
585                         /* Ensure null termination */
586                         plaintext_password.data[passlen1] = 0;
587                 }
588                 
589                 p += passlen1 + passlen2;
590                 p += srvstr_pull(inbuf, user, p, sizeof(user), -1,
591                                  STR_TERMINATE);
592                 p += srvstr_pull(inbuf, domain, p, sizeof(domain), 
593                                  -1, STR_TERMINATE);
594                 p += srvstr_pull(inbuf, native_os, p, sizeof(native_os), 
595                                  -1, STR_TERMINATE);
596                 p += srvstr_pull(inbuf, native_lanman, p, sizeof(native_lanman),
597                                  -1, STR_TERMINATE);
598                 DEBUG(3,("Domain=[%s]  NativeOS=[%s] NativeLanMan=[%s]\n",
599                          domain,native_os,native_lanman));
600         }
601         
602         /* don't allow for weird usernames or domains */
603         alpha_strcpy(user, user, ". _-$", sizeof(user));
604         alpha_strcpy(domain, domain, ". _-", sizeof(domain));
605         if (strstr(user, "..") || strstr(domain,"..")) {
606                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
607         }
608
609         DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n", domain, user, remote_machine));
610
611         if (*user) {
612                 if (global_spnego_negotiated) {
613                         DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt at 'normal' session setup after negotiating spnego.\n"));
614                         return ERROR_NT(NT_STATUS_UNSUCCESSFUL);
615                 }
616         }
617
618         if (*user) {
619                 pstrcpy(sub_user, user);
620         } else {
621                 pstrcpy(sub_user, lp_guestaccount());
622         }
623
624         pstrcpy(current_user_info.smb_name,sub_user);
625
626         reload_services(True);
627         
628         if (lp_security() == SEC_SHARE) {
629                 /* in share level we should ignore any passwords */
630
631                 data_blob_free(&lm_resp);
632                 data_blob_free(&nt_resp);
633                 data_blob_clear_free(&plaintext_password);
634
635                 map_username(sub_user);
636                 add_session_user(sub_user);
637                 /* Then force it to null for the benfit of the code below */
638                 *user = 0;
639         }
640         
641         if (!make_user_info_for_reply(&user_info, 
642                                       user, domain, 
643                                       lm_resp, nt_resp,
644                                       plaintext_password, doencrypt)) {
645                 return ERROR_NT(NT_STATUS_NO_MEMORY);
646         }
647         
648         nt_status = check_password(user_info, &server_info); 
649         
650         free_user_info(&user_info);
651         
652         data_blob_free(&lm_resp);
653         data_blob_free(&nt_resp);
654         data_blob_clear_free(&plaintext_password);
655         
656         if (!NT_STATUS_IS_OK(nt_status)) {
657                 if NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_SUCH_USER) {
658                         if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) || 
659                             (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) {
660                                 
661                                 DEBUG(3,("No such user %s [%s] - using guest account\n",user, domain));
662                                 make_server_info_guest(&server_info);
663                                 nt_status = NT_STATUS_OK;
664                         }
665
666                 } else if NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD) {                        
667                         if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) {                                
668                                 DEBUG(3,("Registered username %s for guest access\n",user));
669                                 make_server_info_guest(&server_info);
670                                 nt_status = NT_STATUS_OK;
671                         }
672                 }
673         }
674         
675         if (!NT_STATUS_IS_OK(nt_status)) {
676                 return ERROR_NT(nt_status_squash(nt_status));
677         }
678         
679         /* it's ok - setup a reply */
680         if (Protocol < PROTOCOL_NT1) {
681                 set_message(outbuf,3,0,True);
682         } else {
683                 char *p;
684                 set_message(outbuf,3,0,True);
685                 p = smb_buf(outbuf);
686                 p += srvstr_push(outbuf, p, "Unix", -1, STR_TERMINATE);
687                 p += srvstr_push(outbuf, p, "Samba", -1, STR_TERMINATE);
688                 p += srvstr_push(outbuf, p, lp_workgroup(), -1, STR_TERMINATE);
689                 set_message_end(outbuf,p);
690                 /* perhaps grab OS version here?? */
691         }
692         
693         if (server_info->guest) {
694                 SSVAL(outbuf,smb_vwv2,1);
695         } else {
696                 const char *home_dir = pdb_get_homedir(server_info->sam_account);
697                 const char *username = pdb_get_username(server_info->sam_account);
698                 if ((home_dir && *home_dir)
699                     && (lp_servicenumber(username) < 0)) {
700                         add_home_service(username, home_dir);     
701                 }
702         }
703
704         /* register the name and uid as being validated, so further connections
705            to a uid can get through without a password, on the same VC */
706
707         sess_vuid = register_vuid(server_info, sub_user);
708
709         free_server_info(&server_info);
710   
711         if (sess_vuid == -1) {
712                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
713         }
714
715  
716         SSVAL(outbuf,smb_uid,sess_vuid);
717         SSVAL(inbuf,smb_uid,sess_vuid);
718         
719         if (!done_sesssetup)
720                 max_send = MIN(max_send,smb_bufsize);
721         
722         done_sesssetup = True;
723         
724         END_PROFILE(SMBsesssetupX);
725         return chain_reply(inbuf,outbuf,length,bufsize);
726 }