added a REALLY gross hack into kerberos_kinit_password so that
[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 static auth_authsupplied_info *ntlmssp_auth_info;
27
28 /****************************************************************************
29  Add the standard 'Samba' signature to the end of the session setup.
30 ****************************************************************************/
31 static void add_signature(char *outbuf) 
32 {
33         char *p;
34         p = smb_buf(outbuf);
35         p += srvstr_push(outbuf, p, "Unix", -1, STR_TERMINATE);
36         p += srvstr_push(outbuf, p, "Samba", -1, STR_TERMINATE);
37         p += srvstr_push(outbuf, p, lp_workgroup(), -1, STR_TERMINATE);
38         set_message_end(outbuf,p);
39 }
40
41 /****************************************************************************
42  Do a 'guest' logon, getting back the 
43 ****************************************************************************/
44 static NTSTATUS check_guest_password(auth_serversupplied_info **server_info) 
45 {
46
47         auth_authsupplied_info *auth_info;
48         auth_usersupplied_info *user_info = NULL;
49         
50         NTSTATUS nt_status;
51         char chal[8];
52
53         ZERO_STRUCT(chal);
54
55         DEBUG(3,("Got anonymous request\n"));
56
57         make_user_info_guest(&user_info);
58         make_auth_info_fixed(&auth_info, chal);
59         
60         nt_status = check_password(user_info, auth_info, server_info);
61         free_auth_info(&auth_info);
62         free_user_info(&user_info);
63         return nt_status;
64 }
65
66
67 #ifdef HAVE_KRB5
68 /****************************************************************************
69 reply to a session setup spnego negotiate packet for kerberos
70 ****************************************************************************/
71 static int reply_spnego_kerberos(connection_struct *conn, 
72                                  char *inbuf, char *outbuf,
73                                  int length, int bufsize,
74                                  DATA_BLOB *secblob)
75 {
76         DATA_BLOB ticket;
77         char *client, *p;
78         const struct passwd *pw;
79         char *user;
80         int sess_vuid;
81         NTSTATUS ret;
82         DATA_BLOB auth_data;
83         auth_serversupplied_info *server_info = NULL;
84         ADS_STRUCT *ads;
85
86         if (!spnego_parse_krb5_wrap(*secblob, &ticket)) {
87                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
88         }
89
90         ads = ads_init(NULL, NULL, NULL, NULL);
91
92         ret = ads_verify_ticket(ads, &ticket, &client, &auth_data);
93         if (!NT_STATUS_IS_OK(ret)) {
94                 DEBUG(1,("Failed to verify incoming ticket!\n"));       
95                 ads_destroy(&ads);
96                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
97         }
98
99         DEBUG(3,("Ticket name is [%s]\n", client));
100
101         p = strchr_m(client, '@');
102         if (!p) {
103                 DEBUG(3,("Doesn't look like a valid principal\n"));
104                 ads_destroy(&ads);
105                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
106         }
107
108         *p = 0;
109         if (strcasecmp(p+1, ads->realm) != 0) {
110                 DEBUG(3,("Ticket for incorrect realm %s\n", p+1));
111                 ads_destroy(&ads);
112                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
113         }
114         ads_destroy(&ads);
115
116         user = client;
117
118         /* the password is good - let them in */
119         pw = smb_getpwnam(user,False);
120         if (!pw) {
121                 DEBUG(1,("Username %s is invalid on this system\n",user));
122                 return ERROR_NT(NT_STATUS_NO_SUCH_USER);
123         }
124
125         if (!make_server_info_pw(&server_info,pw)) {
126                 DEBUG(1,("make_server_info_from_pw failed!\n"));
127                 return ERROR_NT(NT_STATUS_NO_MEMORY);
128         }
129         
130         sess_vuid = register_vuid(server_info, user);
131
132         free_server_info(&server_info);
133
134         if (sess_vuid == -1) {
135                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
136         }
137
138         set_message(outbuf,4,0,True);
139         SSVAL(outbuf, smb_vwv3, 0);
140         add_signature(outbuf);
141  
142         SSVAL(outbuf,smb_uid,sess_vuid);
143         SSVAL(inbuf,smb_uid,sess_vuid);
144         
145         return chain_reply(inbuf,outbuf,length,bufsize);
146 }
147 #endif
148
149
150 /****************************************************************************
151 send a security blob via a session setup reply
152 ****************************************************************************/
153 static BOOL reply_sesssetup_blob(connection_struct *conn, char *outbuf,
154                                  DATA_BLOB blob)
155 {
156         char *p;
157
158         set_message(outbuf,4,0,True);
159
160         /* we set NT_STATUS_MORE_PROCESSING_REQUIRED to tell the other end
161            that we aren't finished yet */
162
163         SIVAL(outbuf, smb_rcls, NT_STATUS_V(NT_STATUS_MORE_PROCESSING_REQUIRED));
164         SSVAL(outbuf, smb_vwv0, 0xFF); /* no chaining possible */
165         SSVAL(outbuf, smb_vwv3, blob.length);
166         p = smb_buf(outbuf);
167         memcpy(p, blob.data, blob.length);
168         p += blob.length;
169         p += srvstr_push(outbuf, p, "Unix", -1, STR_TERMINATE);
170         p += srvstr_push(outbuf, p, "Samba", -1, STR_TERMINATE);
171         p += srvstr_push(outbuf, p, lp_workgroup(), -1, STR_TERMINATE);
172         set_message_end(outbuf,p);
173         
174         return send_smb(smbd_server_fd(),outbuf);
175 }
176
177 /****************************************************************************
178 reply to a session setup spnego negotiate packet
179 ****************************************************************************/
180 static int reply_spnego_negotiate(connection_struct *conn, 
181                                   char *inbuf,
182                                   char *outbuf,
183                                   int length, int bufsize,
184                                   DATA_BLOB blob1)
185 {
186         char *OIDs[ASN1_MAX_OIDS];
187         DATA_BLOB secblob;
188         int i;
189         uint32 ntlmssp_command, neg_flags;
190         DATA_BLOB sess_key, chal, spnego_chal;
191         DATA_BLOB cryptkey;
192         BOOL got_kerberos = False;
193
194         /* parse out the OIDs and the first sec blob */
195         if (!parse_negTokenTarg(blob1, OIDs, &secblob)) {
196                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
197         }
198         
199         for (i=0;OIDs[i];i++) {
200                 DEBUG(3,("Got OID %s\n", OIDs[i]));
201                 if (strcmp(OID_KERBEROS5, OIDs[i]) == 0 ||
202                     strcmp(OID_KERBEROS5_OLD, OIDs[i]) == 0) {
203                         got_kerberos = True;
204                 }
205                 free(OIDs[i]);
206         }
207         DEBUG(3,("Got secblob of size %d\n", secblob.length));
208
209 #ifdef HAVE_KRB5
210         if (got_kerberos) {
211                 int ret = reply_spnego_kerberos(conn, inbuf, outbuf, 
212                                                 length, bufsize, &secblob);
213                 data_blob_free(&secblob);
214                 return ret;
215         }
216 #endif
217
218         /* parse the NTLMSSP packet */
219 #if 0
220         file_save("secblob.dat", secblob.data, secblob.length);
221 #endif
222
223         if (!msrpc_parse(&secblob, "CddB",
224                          "NTLMSSP",
225                          &ntlmssp_command,
226                          &neg_flags,
227                          &sess_key)) {
228                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
229         }
230
231         data_blob_free(&secblob);
232         data_blob_free(&sess_key);
233
234         if (ntlmssp_command != NTLMSSP_NEGOTIATE) {
235                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
236         }
237
238         DEBUG(3,("Got neg_flags=%08x\n", neg_flags));
239
240         if (!make_auth_info_subsystem(&ntlmssp_auth_info)) {
241                 return ERROR_NT(NT_STATUS_NO_MEMORY);
242         }
243
244         cryptkey = auth_get_challenge(ntlmssp_auth_info);
245
246         /* Give them the challenge. For now, ignore neg_flags and just
247            return the flags we want. Obviously this is not correct */
248         
249         neg_flags = NTLMSSP_NEGOTIATE_UNICODE | 
250                 NTLMSSP_NEGOTIATE_LM_KEY | 
251                 NTLMSSP_NEGOTIATE_NTLM;
252
253         msrpc_gen(&chal, "Cddddbdddd",
254                   "NTLMSSP", 
255                   NTLMSSP_CHALLENGE,
256                   0,
257                   0x30, /* ?? */
258                   neg_flags,
259                   cryptkey.data, cryptkey.length,
260                   0, 0, 0,
261                   0x3000); /* ?? */
262
263         if (!spnego_gen_challenge(&spnego_chal, &chal, &chal)) {
264                 DEBUG(3,("Failed to generate challenge\n"));
265                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
266         }
267
268         /* now tell the client to send the auth packet */
269         reply_sesssetup_blob(conn, outbuf, spnego_chal);
270
271         data_blob_free(&chal);
272         data_blob_free(&cryptkey);
273         data_blob_free(&spnego_chal);
274
275         /* and tell smbd that we have already replied to this packet */
276         return -1;
277 }
278
279         
280 /****************************************************************************
281 reply to a session setup spnego auth packet
282 ****************************************************************************/
283 static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
284                              int length, int bufsize,
285                              DATA_BLOB blob1)
286 {
287         DATA_BLOB auth;
288         char *workgroup = NULL, *user = NULL, *machine = NULL;
289         DATA_BLOB lmhash, nthash, sess_key;
290         DATA_BLOB plaintext_password = data_blob(NULL, 0);
291         uint32 ntlmssp_command, neg_flags;
292         NTSTATUS nt_status;
293         int sess_vuid;
294
295         auth_usersupplied_info *user_info = NULL;
296         auth_serversupplied_info *server_info = NULL;
297
298         if (!spnego_parse_auth(blob1, &auth)) {
299 #if 0
300                 file_save("auth.dat", blob1.data, blob1.length);
301 #endif
302                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
303         }
304
305         /* now the NTLMSSP encoded auth hashes */
306         if (!msrpc_parse(&auth, "CdBBUUUBd", 
307                          "NTLMSSP", 
308                          &ntlmssp_command, 
309                          &lmhash,
310                          &nthash,
311                          &workgroup, 
312                          &user, 
313                          &machine,
314                          &sess_key,
315                          &neg_flags)) {
316                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
317         }
318
319         data_blob_free(&auth);
320         data_blob_free(&sess_key);
321         
322         DEBUG(3,("Got user=[%s] workgroup=[%s] machine=[%s] len1=%d len2=%d\n",
323                  user, workgroup, machine, lmhash.length, nthash.length));
324
325 #if 0
326         file_save("nthash1.dat", nthash.data, nthash.length);
327         file_save("lmhash1.dat", lmhash.data, lmhash.length);
328 #endif
329
330         if (!make_user_info_map(&user_info, 
331                                 user, workgroup, 
332                                 machine, 
333                                 lmhash, nthash,
334                                 plaintext_password, 
335                                 neg_flags, True)) {
336                 return ERROR_NT(NT_STATUS_NO_MEMORY);
337         }
338
339         SAFE_FREE(workgroup);
340         SAFE_FREE(user);
341         SAFE_FREE(machine);
342         
343         nt_status = check_password(user_info, ntlmssp_auth_info, &server_info); 
344         
345         free_auth_info(&ntlmssp_auth_info);
346
347         free_user_info(&user_info);
348         
349         data_blob_free(&lmhash);
350         
351         data_blob_free(&nthash);
352         
353         if (!NT_STATUS_IS_OK(nt_status)) {
354                 return ERROR_NT(nt_status_squash(nt_status));
355         }
356
357         sess_vuid = register_vuid(server_info, user);
358
359         free_server_info(&server_info);
360   
361         if (sess_vuid == -1) {
362                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
363         }
364
365         set_message(outbuf,4,0,True);
366         SSVAL(outbuf, smb_vwv3, 0);
367         add_signature(outbuf);
368  
369         SSVAL(outbuf,smb_uid,sess_vuid);
370         SSVAL(inbuf,smb_uid,sess_vuid);
371         
372         return chain_reply(inbuf,outbuf,length,bufsize);
373 }
374
375
376 /****************************************************************************
377 reply to a session setup spnego anonymous packet
378 ****************************************************************************/
379 static int reply_spnego_anonymous(connection_struct *conn, char *inbuf, char *outbuf,
380                                   int length, int bufsize)
381 {
382         int sess_vuid;
383         auth_serversupplied_info *server_info = NULL;
384         NTSTATUS nt_status;
385
386         nt_status = check_guest_password(&server_info);
387
388         if (!NT_STATUS_IS_OK(nt_status)) {
389                 return ERROR_NT(nt_status_squash(nt_status));
390         }
391
392         sess_vuid = register_vuid(server_info, lp_guestaccount());
393
394         free_server_info(&server_info);
395   
396         if (sess_vuid == -1) {
397                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
398         }
399
400         set_message(outbuf,4,0,True);
401         SSVAL(outbuf, smb_vwv3, 0);
402         add_signature(outbuf);
403  
404         SSVAL(outbuf,smb_uid,sess_vuid);
405         SSVAL(inbuf,smb_uid,sess_vuid);
406         
407         return chain_reply(inbuf,outbuf,length,bufsize);
408 }
409
410
411 /****************************************************************************
412 reply to a session setup command
413 ****************************************************************************/
414 static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,char *outbuf,
415                                         int length,int bufsize)
416 {
417         uint8 *p;
418         DATA_BLOB blob1;
419         int ret;
420
421         DEBUG(3,("Doing spnego session setup\n"));
422
423         if (global_client_caps == 0) {
424                 global_client_caps = IVAL(inbuf,smb_vwv10);
425         }
426                 
427         p = (uint8 *)smb_buf(inbuf);
428
429         if (SVAL(inbuf, smb_vwv7) == 0) {
430                 /* an anonymous request */
431                 return reply_spnego_anonymous(conn, inbuf, outbuf, length, bufsize);
432         }
433
434         /* pull the spnego blob */
435         blob1 = data_blob(p, SVAL(inbuf, smb_vwv7));
436
437 #if 0
438         file_save("negotiate.dat", blob1.data, blob1.length);
439 #endif
440
441         if (blob1.data[0] == ASN1_APPLICATION(0)) {
442                 /* its a negTokenTarg packet */
443                 ret = reply_spnego_negotiate(conn, inbuf, outbuf, length, bufsize, blob1);
444                 data_blob_free(&blob1);
445                 return ret;
446         }
447
448         if (blob1.data[0] == ASN1_CONTEXT(1)) {
449                 /* its a auth packet */
450                 ret = reply_spnego_auth(conn, inbuf, outbuf, length, bufsize, blob1);
451                 data_blob_free(&blob1);
452                 return ret;
453         }
454
455         /* what sort of packet is this? */
456         DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
457
458         data_blob_free(&blob1);
459
460         return ERROR_NT(NT_STATUS_LOGON_FAILURE);
461 }
462
463
464 /****************************************************************************
465 reply to a session setup command
466 ****************************************************************************/
467 int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
468                           int length,int bufsize)
469 {
470         int sess_vuid;
471         int   smb_bufsize;    
472         DATA_BLOB lm_resp;
473         DATA_BLOB nt_resp;
474         DATA_BLOB plaintext_password;
475         pstring user;
476         pstring sub_user; /* Sainitised username for substituion */
477         fstring domain;
478         fstring native_os;
479         fstring native_lanman;
480         static BOOL done_sesssetup = False;
481         extern BOOL global_encrypted_passwords_negotiated;
482         extern BOOL global_spnego_negotiated;
483         extern int Protocol;
484         extern fstring remote_machine;
485         extern userdom_struct current_user_info;
486         extern int max_send;
487
488         auth_usersupplied_info *user_info = NULL;
489         extern auth_authsupplied_info *negprot_global_auth_info;
490         auth_serversupplied_info *server_info = NULL;
491
492         NTSTATUS nt_status;
493
494         BOOL doencrypt = global_encrypted_passwords_negotiated;
495
496         START_PROFILE(SMBsesssetupX);
497
498         ZERO_STRUCT(lm_resp);
499         ZERO_STRUCT(nt_resp);
500         ZERO_STRUCT(plaintext_password);
501
502         DEBUG(3,("wct=%d flg2=0x%x\n", CVAL(inbuf, smb_wct), SVAL(inbuf, smb_flg2)));
503         
504         /* a SPNEGO session setup has 12 command words, whereas a normal
505            NT1 session setup has 13. See the cifs spec. */
506         if (CVAL(inbuf, smb_wct) == 12 &&
507             (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
508                 return reply_sesssetup_and_X_spnego(conn, inbuf, outbuf, length, bufsize);
509         }
510
511         smb_bufsize = SVAL(inbuf,smb_vwv2);
512
513         if (Protocol < PROTOCOL_NT1) {
514                 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
515                 if (passlen1 > MAX_PASS_LEN) {
516                         return ERROR_DOS(ERRDOS,ERRbuftoosmall);
517                 }
518
519                 if (doencrypt) {
520                         lm_resp = data_blob(smb_buf(inbuf), passlen1);
521                 } else {
522                         plaintext_password = data_blob(smb_buf(inbuf), passlen1+1);
523                         /* Ensure null termination */
524                         plaintext_password.data[passlen1] = 0;
525                 }
526
527                 srvstr_pull(inbuf, user, smb_buf(inbuf)+passlen1, sizeof(user), -1, STR_TERMINATE);
528                 *domain = 0;
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 (!*user) {
642
643                 nt_status = check_guest_password(&server_info);
644
645         } else if (doencrypt) {
646                 if (!make_user_info_for_reply_enc(&user_info, 
647                                                   user, domain, 
648                                                   lm_resp, nt_resp,
649                                                   plaintext_password)) {
650                         return ERROR_NT(NT_STATUS_NO_MEMORY);
651                 }
652                 
653                 nt_status = check_password(user_info, negprot_global_auth_info, &server_info); 
654
655         } else {
656                 auth_authsupplied_info *plaintext_auth_info = NULL;
657                 DATA_BLOB chal;
658                 if (!make_auth_info_subsystem(&plaintext_auth_info)) {
659                         return ERROR_NT(NT_STATUS_NO_MEMORY);
660                 }
661
662                 chal = auth_get_challenge(plaintext_auth_info);
663
664                 if (!make_user_info_for_reply(&user_info, 
665                                               user, domain, chal.data,
666                                               plaintext_password)) {
667                         return ERROR_NT(NT_STATUS_NO_MEMORY);
668                 }
669                 
670                 nt_status = check_password(user_info, plaintext_auth_info, &server_info); 
671                 
672                 data_blob_free(&chal);
673                 free_auth_info(&plaintext_auth_info);
674         }
675
676         free_user_info(&user_info);
677         
678         data_blob_free(&lm_resp);
679         data_blob_free(&nt_resp);
680         data_blob_clear_free(&plaintext_password);
681         
682         if (!NT_STATUS_IS_OK(nt_status)) {
683                 if NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_SUCH_USER) {
684                         if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) || 
685                             (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) {
686                                 
687                                 DEBUG(3,("No such user %s [%s] - using guest account\n",user, domain));
688                                 make_server_info_guest(&server_info);
689                                 nt_status = NT_STATUS_OK;
690                         }
691
692                 } else if NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD) {                        
693                         if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) {                                
694                                 DEBUG(3,("Registered username %s for guest access\n",user));
695                                 make_server_info_guest(&server_info);
696                                 nt_status = NT_STATUS_OK;
697                         }
698                 }
699         }
700         
701         if (!NT_STATUS_IS_OK(nt_status)) {
702                 return ERROR_NT(nt_status_squash(nt_status));
703         }
704         
705         /* it's ok - setup a reply */
706         if (Protocol < PROTOCOL_NT1) {
707                 set_message(outbuf,3,0,True);
708         } else {
709                 set_message(outbuf,3,0,True);
710                 add_signature(outbuf);
711                 /* perhaps grab OS version here?? */
712         }
713         
714         if (server_info->guest) {
715                 SSVAL(outbuf,smb_vwv2,1);
716         } else {
717                 const char *home_dir = pdb_get_homedir(server_info->sam_account);
718                 const char *username = pdb_get_username(server_info->sam_account);
719                 if ((home_dir && *home_dir)
720                     && (lp_servicenumber(username) < 0)) {
721                         add_home_service(username, home_dir);     
722                 }
723         }
724
725         /* register the name and uid as being validated, so further connections
726            to a uid can get through without a password, on the same VC */
727
728         sess_vuid = register_vuid(server_info, sub_user);
729
730         free_server_info(&server_info);
731   
732         if (sess_vuid == -1) {
733                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
734         }
735
736  
737         SSVAL(outbuf,smb_uid,sess_vuid);
738         SSVAL(inbuf,smb_uid,sess_vuid);
739         
740         if (!done_sesssetup)
741                 max_send = MIN(max_send,smb_bufsize);
742         
743         done_sesssetup = True;
744         
745         END_PROFILE(SMBsesssetupX);
746         return chain_reply(inbuf,outbuf,length,bufsize);
747 }
748
749
750
751
752