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