more 2.2.x compatibility fixes - allow user looksup in the kerb5
[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 <jmcd@us.ibm.com> 2002
7    Copyright (C) Luke Howard          2003
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25
26 uint32 global_client_caps = 0;
27
28 static struct auth_ntlmssp_state *global_ntlmssp_state;
29
30 /*
31   on a logon error possibly map the error to success if "map to guest"
32   is set approriately
33 */
34 static NTSTATUS do_map_to_guest(NTSTATUS status, auth_serversupplied_info **server_info,
35                                 const char *user, const char *domain)
36 {
37         if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
38                 if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) || 
39                     (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) {
40                         DEBUG(3,("No such user %s [%s] - using guest account\n",
41                                  user, domain));
42                         status = make_server_info_guest(server_info);
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                         status = make_server_info_guest(server_info);
50                 }
51         }
52
53         return status;
54 }
55
56 /****************************************************************************
57  Add the standard 'Samba' signature to the end of the session setup.
58 ****************************************************************************/
59
60 static int add_signature(char *outbuf, char *p)
61 {
62         char *start = p;
63         fstring lanman;
64
65         fstr_sprintf( lanman, "Samba %s", SAMBA_VERSION_STRING);
66
67         p += srvstr_push(outbuf, p, "Unix", -1, STR_TERMINATE);
68         p += srvstr_push(outbuf, p, lanman, -1, STR_TERMINATE);
69         p += srvstr_push(outbuf, p, lp_workgroup(), -1, STR_TERMINATE);
70
71         return PTR_DIFF(p, start);
72 }
73
74 /****************************************************************************
75  Send a security blob via a session setup reply.
76 ****************************************************************************/
77
78 static BOOL reply_sesssetup_blob(connection_struct *conn, char *outbuf,
79                                  DATA_BLOB blob, NTSTATUS nt_status)
80 {
81         char *p;
82
83         set_message(outbuf,4,0,True);
84
85         nt_status = nt_status_squash(nt_status);
86         SIVAL(outbuf, smb_rcls, NT_STATUS_V(nt_status));
87         SSVAL(outbuf, smb_vwv0, 0xFF); /* no chaining possible */
88         SSVAL(outbuf, smb_vwv3, blob.length);
89         p = smb_buf(outbuf);
90
91         /* should we cap this? */
92         memcpy(p, blob.data, blob.length);
93         p += blob.length;
94
95         p += add_signature( outbuf, p );
96
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
106 static NTSTATUS check_guest_password(auth_serversupplied_info **server_info) 
107 {
108         struct auth_context *auth_context;
109         auth_usersupplied_info *user_info = NULL;
110         
111         NTSTATUS nt_status;
112         unsigned char chal[8];
113
114         ZERO_STRUCT(chal);
115
116         DEBUG(3,("Got anonymous request\n"));
117
118         if (!NT_STATUS_IS_OK(nt_status = make_auth_context_fixed(&auth_context, chal))) {
119                 return nt_status;
120         }
121
122         if (!make_user_info_guest(&user_info)) {
123                 (auth_context->free)(&auth_context);
124                 return NT_STATUS_NO_MEMORY;
125         }
126         
127         nt_status = auth_context->check_ntlm_password(auth_context, user_info, server_info);
128         (auth_context->free)(&auth_context);
129         free_user_info(&user_info);
130         return nt_status;
131 }
132
133
134 #ifdef HAVE_KRB5
135 /****************************************************************************
136 reply to a session setup spnego negotiate packet for kerberos
137 ****************************************************************************/
138 static int reply_spnego_kerberos(connection_struct *conn, 
139                                  char *inbuf, char *outbuf,
140                                  int length, int bufsize,
141                                  DATA_BLOB *secblob)
142 {
143         DATA_BLOB ticket;
144         char *client, *p;
145         const struct passwd *pw;
146         char *user;
147         int sess_vuid;
148         NTSTATUS ret;
149         DATA_BLOB auth_data;
150         DATA_BLOB ap_rep, ap_rep_wrapped, response;
151         auth_serversupplied_info *server_info = NULL;
152         uint8 session_key[16];
153         uint8 tok_id[2];
154         BOOL foreign = False;
155         DATA_BLOB nullblob = data_blob(NULL, 0);
156
157         ZERO_STRUCT(ticket);
158         ZERO_STRUCT(auth_data);
159         ZERO_STRUCT(ap_rep);
160         ZERO_STRUCT(ap_rep_wrapped);
161         ZERO_STRUCT(response);
162
163         if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) {
164                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
165         }
166
167         ret = ads_verify_ticket(lp_realm(), &ticket, &client, &auth_data, &ap_rep, session_key);
168
169         data_blob_free(&ticket);
170
171         if (!NT_STATUS_IS_OK(ret)) {
172                 DEBUG(1,("Failed to verify incoming ticket!\n"));       
173                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
174         }
175
176         data_blob_free(&auth_data);
177
178         DEBUG(3,("Ticket name is [%s]\n", client));
179
180         p = strchr_m(client, '@');
181         if (!p) {
182                 DEBUG(3,("Doesn't look like a valid principal\n"));
183                 data_blob_free(&ap_rep);
184                 SAFE_FREE(client);
185                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
186         }
187
188         *p = 0;
189         if (strcasecmp(p+1, lp_realm()) != 0) {
190                 DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1));
191                 if (!lp_allow_trusted_domains()) {
192                         data_blob_free(&ap_rep);
193                         SAFE_FREE(client);
194                         return ERROR_NT(NT_STATUS_LOGON_FAILURE);
195                 }
196                 foreign = True;
197         }
198
199         /* this gives a fully qualified user name (ie. with full realm).
200            that leads to very long usernames, but what else can we do? */
201            
202         asprintf(&user, "%s%c%s", p+1, *lp_winbind_separator(), client);
203         
204         pw = smb_getpwnam( user );
205         
206         SAFE_FREE(user);
207         SAFE_FREE(client);
208
209         if (!pw) {
210                 DEBUG(1,("Username %s is invalid on this system\n",user));
211                 data_blob_free(&ap_rep);
212                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
213         }
214
215         /* setup the string used by %U */
216         
217         sub_set_smb_name(pw->pw_name);
218         reload_services(True);
219         
220         if (!NT_STATUS_IS_OK(ret = make_server_info_pw(&server_info,pw))) {
221                 DEBUG(1,("make_server_info_from_pw failed!\n"));
222                 data_blob_free(&ap_rep);
223                 return ERROR_NT(ret);
224         }
225
226         /* Copy out the session key from the AP_REQ. */
227         memcpy(server_info->session_key, session_key, sizeof(session_key));
228
229         /* register_vuid keeps the server info */
230         sess_vuid = register_vuid(server_info, nullblob, user);
231
232         free(user);
233
234         if (sess_vuid == -1) {
235                 ret = NT_STATUS_LOGON_FAILURE;
236         } else {
237                 set_message(outbuf,4,0,True);
238                 SSVAL(outbuf, smb_vwv3, 0);
239                         
240                 if (server_info->guest) {
241                         SSVAL(outbuf,smb_vwv2,1);
242                 }
243                 
244                 SSVAL(outbuf, smb_uid, sess_vuid);
245
246                 if (!server_info->guest) {
247                         /* We need to start the signing engine
248                          * here but a W2K client sends the old
249                          * "BSRSPYL " signature instead of the
250                          * correct one. Subsequent packets will
251                          * be correct.
252                          */
253                         srv_check_sign_mac(inbuf);
254                 }
255         }
256
257         /* wrap that up in a nice GSS-API wrapping */
258         if (NT_STATUS_IS_OK(ret)) {
259                 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep, TOK_ID_KRB_AP_REP);
260         } else {
261                 ap_rep_wrapped = data_blob(NULL, 0);
262         }
263         response = spnego_gen_auth_response(&ap_rep_wrapped, ret, OID_KERBEROS5_OLD);
264         reply_sesssetup_blob(conn, outbuf, response, ret);
265
266         data_blob_free(&ap_rep);
267         data_blob_free(&ap_rep_wrapped);
268         data_blob_free(&response);
269
270         return -1; /* already replied */
271 }
272 #endif
273
274 /****************************************************************************
275  Send a session setup reply, wrapped in SPNEGO.
276  Get vuid and check first.
277  End the NTLMSSP exchange context if we are OK/complete fail
278 ***************************************************************************/
279
280 static BOOL reply_spnego_ntlmssp(connection_struct *conn, char *inbuf, char *outbuf,
281                                  AUTH_NTLMSSP_STATE **auth_ntlmssp_state,
282                                  DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status) 
283 {
284         BOOL ret;
285         DATA_BLOB response;
286         struct auth_serversupplied_info *server_info = NULL;
287
288         if (NT_STATUS_IS_OK(nt_status)) {
289                 server_info = (*auth_ntlmssp_state)->server_info;
290         } else {
291                 nt_status = do_map_to_guest(nt_status, 
292                                             &server_info, 
293                                             (*auth_ntlmssp_state)->ntlmssp_state->user, 
294                                             (*auth_ntlmssp_state)->ntlmssp_state->domain);
295         }
296
297         if (NT_STATUS_IS_OK(nt_status)) {
298                 int sess_vuid;
299                 DATA_BLOB nullblob = data_blob(NULL, 0);
300
301                 /* register_vuid keeps the server info */
302                 sess_vuid = register_vuid(server_info, nullblob, (*auth_ntlmssp_state)->ntlmssp_state->user);
303                 (*auth_ntlmssp_state)->server_info = NULL;
304
305                 if (sess_vuid == -1) {
306                         nt_status = NT_STATUS_LOGON_FAILURE;
307                 } else {
308                         
309                         set_message(outbuf,4,0,True);
310                         SSVAL(outbuf, smb_vwv3, 0);
311                         
312                         if (server_info->guest) {
313                                 SSVAL(outbuf,smb_vwv2,1);
314                         }
315                         
316                         SSVAL(outbuf,smb_uid,sess_vuid);
317
318                         if (!server_info->guest) {
319                                 /* We need to start the signing engine
320                                  * here but a W2K client sends the old
321                                  * "BSRSPYL " signature instead of the
322                                  * correct one. Subsequent packets will
323                                  * be correct.
324                                  */
325                                 srv_check_sign_mac(inbuf);
326                         }
327                 }
328         }
329
330         response = spnego_gen_auth_response(ntlmssp_blob, nt_status, OID_NTLMSSP);
331         ret = reply_sesssetup_blob(conn, outbuf, response, nt_status);
332         data_blob_free(&response);
333
334         /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
335            and the other end, that we are not finished yet. */
336
337         if (!ret || !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
338                 auth_ntlmssp_end(auth_ntlmssp_state);
339         }
340
341         return ret;
342 }
343
344 /****************************************************************************
345  Reply to a session setup spnego negotiate packet.
346 ****************************************************************************/
347
348 static int reply_spnego_negotiate(connection_struct *conn, 
349                                   char *inbuf,
350                                   char *outbuf,
351                                   int length, int bufsize,
352                                   DATA_BLOB blob1)
353 {
354         char *OIDs[ASN1_MAX_OIDS];
355         DATA_BLOB secblob;
356         int i;
357         DATA_BLOB chal;
358         BOOL got_kerberos = False;
359         NTSTATUS nt_status;
360
361         /* parse out the OIDs and the first sec blob */
362         if (!parse_negTokenTarg(blob1, OIDs, &secblob)) {
363                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
364         }
365
366         /* only look at the first OID for determining the mechToken --
367            accoirding to RFC2478, we should choose the one we want 
368            and renegotiate, but i smell a client bug here..  
369            
370            Problem observed when connecting to a member (samba box) 
371            of an AD domain as a user in a Samba domain.  Samba member 
372            server sent back krb5/mskrb5/ntlmssp as mechtypes, but the 
373            client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an 
374            NTLMSSP mechtoken.                 --jerry              */
375         
376         if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||
377             strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
378                 got_kerberos = True;
379         }
380                 
381         for (i=0;OIDs[i];i++) {
382                 DEBUG(3,("Got OID %s\n", OIDs[i]));
383                 free(OIDs[i]);
384         }
385         DEBUG(3,("Got secblob of size %lu\n", (unsigned long)secblob.length));
386
387 #ifdef HAVE_KRB5
388         if (got_kerberos && (SEC_ADS == lp_security())) {
389                 int ret = reply_spnego_kerberos(conn, inbuf, outbuf, 
390                                                 length, bufsize, &secblob);
391                 data_blob_free(&secblob);
392                 return ret;
393         }
394 #endif
395
396         if (global_ntlmssp_state) {
397                 auth_ntlmssp_end(&global_ntlmssp_state);
398         }
399
400         nt_status = auth_ntlmssp_start(&global_ntlmssp_state);
401         if (!NT_STATUS_IS_OK(nt_status)) {
402                 return ERROR_NT(nt_status);
403         }
404
405         nt_status = auth_ntlmssp_update(global_ntlmssp_state, 
406                                         secblob, &chal);
407
408         data_blob_free(&secblob);
409
410         reply_spnego_ntlmssp(conn, inbuf, outbuf, &global_ntlmssp_state,
411                              &chal, nt_status);
412                 
413         data_blob_free(&chal);
414
415         /* already replied */
416         return -1;
417 }
418         
419 /****************************************************************************
420  Reply to a session setup spnego auth packet.
421 ****************************************************************************/
422
423 static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
424                              int length, int bufsize,
425                              DATA_BLOB blob1)
426 {
427         DATA_BLOB auth, auth_reply;
428         NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
429
430         if (!spnego_parse_auth(blob1, &auth)) {
431 #if 0
432                 file_save("auth.dat", blob1.data, blob1.length);
433 #endif
434                 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
435         }
436         
437         if (!global_ntlmssp_state) {
438                 /* auth before negotiatiate? */
439                 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
440         }
441         
442         nt_status = auth_ntlmssp_update(global_ntlmssp_state, 
443                                                 auth, &auth_reply);
444
445         data_blob_free(&auth);
446
447         reply_spnego_ntlmssp(conn, inbuf, outbuf, &global_ntlmssp_state,
448                              &auth_reply, nt_status);
449                 
450         data_blob_free(&auth_reply);
451
452         /* and tell smbd that we have already replied to this packet */
453         return -1;
454 }
455
456 /****************************************************************************
457  Reply to a session setup command.
458 ****************************************************************************/
459
460 static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,
461                                         char *outbuf,
462                                         int length,int bufsize)
463 {
464         uint8 *p;
465         DATA_BLOB blob1;
466         int ret;
467         size_t bufrem;
468         fstring native_os, native_lanman;
469         char *p2;
470         uint16 data_blob_len = SVAL(inbuf, smb_vwv7);
471         enum remote_arch_types ra_type = get_remote_arch();
472
473         DEBUG(3,("Doing spnego session setup\n"));
474
475         if (global_client_caps == 0) {
476                 global_client_caps = IVAL(inbuf,smb_vwv10);
477         }
478                 
479         p = (uint8 *)smb_buf(inbuf);
480
481         if (data_blob_len == 0) {
482                 /* an invalid request */
483                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
484         }
485
486         bufrem = smb_bufrem(inbuf, p);
487         /* pull the spnego blob */
488         blob1 = data_blob(p, MIN(bufrem, data_blob_len));
489
490 #if 0
491         file_save("negotiate.dat", blob1.data, blob1.length);
492 #endif
493
494         p2 = inbuf + smb_vwv13 + data_blob_len;
495         p2 += srvstr_pull_buf(inbuf, native_os, p2, sizeof(native_os), STR_TERMINATE);
496         p2 += srvstr_pull_buf(inbuf, native_lanman, p2, sizeof(native_lanman), STR_TERMINATE);
497         DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s]\n", native_os, native_lanman));
498
499         if ( ra_type == RA_WIN2K )
500                 ra_lanman_string( native_lanman );
501
502         if (blob1.data[0] == ASN1_APPLICATION(0)) {
503                 /* its a negTokenTarg packet */
504                 ret = reply_spnego_negotiate(conn, inbuf, outbuf, length, bufsize, blob1);
505                 data_blob_free(&blob1);
506                 return ret;
507         }
508
509         if (blob1.data[0] == ASN1_CONTEXT(1)) {
510                 /* its a auth packet */
511                 ret = reply_spnego_auth(conn, inbuf, outbuf, length, bufsize, blob1);
512                 data_blob_free(&blob1);
513                 return ret;
514         }
515
516         /* what sort of packet is this? */
517         DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
518
519         data_blob_free(&blob1);
520
521         return ERROR_NT(NT_STATUS_LOGON_FAILURE);
522 }
523
524 /****************************************************************************
525  On new VC == 0, shutdown *all* old connections and users.
526  It seems that only NT4.x does this. At W2K and above (XP etc.).
527  a new session setup with VC==0 is ignored.
528 ****************************************************************************/
529
530 static void setup_new_vc_session(void)
531 {
532         DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x compatible we would close all old resources.\n"));
533 #if 0
534         conn_close_all();
535         invalidate_all_vuids();
536 #endif
537 }
538
539 /****************************************************************************
540  Reply to a session setup command.
541 ****************************************************************************/
542
543 int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
544                           int length,int bufsize)
545 {
546         int sess_vuid;
547         int   smb_bufsize;    
548         DATA_BLOB lm_resp;
549         DATA_BLOB nt_resp;
550         DATA_BLOB plaintext_password;
551         fstring user;
552         fstring sub_user; /* Sainitised username for substituion */
553         fstring domain;
554         fstring native_os;
555         fstring native_lanman;
556         static BOOL done_sesssetup = False;
557         extern BOOL global_encrypted_passwords_negotiated;
558         extern BOOL global_spnego_negotiated;
559         extern int Protocol;
560         extern int max_send;
561
562         auth_usersupplied_info *user_info = NULL;
563         extern struct auth_context *negprot_global_auth_context;
564         auth_serversupplied_info *server_info = NULL;
565
566         NTSTATUS nt_status;
567
568         BOOL doencrypt = global_encrypted_passwords_negotiated;
569         
570         START_PROFILE(SMBsesssetupX);
571
572         ZERO_STRUCT(lm_resp);
573         ZERO_STRUCT(nt_resp);
574         ZERO_STRUCT(plaintext_password);
575
576         DEBUG(3,("wct=%d flg2=0x%x\n", CVAL(inbuf, smb_wct), SVAL(inbuf, smb_flg2)));
577
578         /* a SPNEGO session setup has 12 command words, whereas a normal
579            NT1 session setup has 13. See the cifs spec. */
580         if (CVAL(inbuf, smb_wct) == 12 &&
581             (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
582                 if (!global_spnego_negotiated) {
583                         DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt at SPNEGO session setup when it was not negoitiated.\n"));
584                         return ERROR_NT(NT_STATUS_UNSUCCESSFUL);
585                 }
586
587                 if (SVAL(inbuf,smb_vwv4) == 0) {
588                         setup_new_vc_session();
589                 }
590                 return reply_sesssetup_and_X_spnego(conn, inbuf, outbuf, length, bufsize);
591         }
592
593         smb_bufsize = SVAL(inbuf,smb_vwv2);
594
595         if (Protocol < PROTOCOL_NT1) {
596                 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
597                 if ((passlen1 > MAX_PASS_LEN) || (passlen1 > smb_bufrem(inbuf, smb_buf(inbuf)))) {
598                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
599                 }
600
601                 if (doencrypt) {
602                         lm_resp = data_blob(smb_buf(inbuf), passlen1);
603                 } else {
604                         plaintext_password = data_blob(smb_buf(inbuf), passlen1+1);
605                         /* Ensure null termination */
606                         plaintext_password.data[passlen1] = 0;
607                 }
608
609                 srvstr_pull_buf(inbuf, user, smb_buf(inbuf)+passlen1, sizeof(user), STR_TERMINATE);
610                 *domain = 0;
611
612         } else {
613                 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
614                 uint16 passlen2 = SVAL(inbuf,smb_vwv8);
615                 enum remote_arch_types ra_type = get_remote_arch();
616                 char *p = smb_buf(inbuf);    
617
618                 if(global_client_caps == 0)
619                         global_client_caps = IVAL(inbuf,smb_vwv11);
620                 
621                 /* client_caps is used as final determination if client is NT or Win95. 
622                    This is needed to return the correct error codes in some
623                    circumstances.
624                 */
625                 
626                 if(ra_type == RA_WINNT || ra_type == RA_WIN2K || ra_type == RA_WIN95) {
627                         if(!(global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))) {
628                                 set_remote_arch( RA_WIN95);
629                         }
630                 }
631
632                 if (!doencrypt) {
633                         /* both Win95 and WinNT stuff up the password lengths for
634                            non-encrypting systems. Uggh. 
635                            
636                            if passlen1==24 its a win95 system, and its setting the
637                            password length incorrectly. Luckily it still works with the
638                            default code because Win95 will null terminate the password
639                            anyway 
640                            
641                            if passlen1>0 and passlen2>0 then maybe its a NT box and its
642                            setting passlen2 to some random value which really stuffs
643                            things up. we need to fix that one.  */
644                         
645                         if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 && passlen2 != 1)
646                                 passlen2 = 0;
647                 }
648                 
649                 /* check for nasty tricks */
650                 if (passlen1 > MAX_PASS_LEN || passlen1 > smb_bufrem(inbuf, p)) {
651                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
652                 }
653
654                 if (passlen2 > MAX_PASS_LEN || passlen2 > smb_bufrem(inbuf, p+passlen1)) {
655                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
656                 }
657
658                 /* Save the lanman2 password and the NT md4 password. */
659                 
660                 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
661                         doencrypt = False;
662                 }
663
664                 if (doencrypt) {
665                         lm_resp = data_blob(p, passlen1);
666                         nt_resp = data_blob(p+passlen1, passlen2);
667                 } else {
668                         pstring pass;
669                         BOOL unic;
670                         unic=SVAL(inbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS;
671                         srvstr_pull(inbuf, pass, smb_buf(inbuf), 
672                                     sizeof(pass),  unic ? passlen2 : passlen1, 
673                                     STR_TERMINATE);
674                         plaintext_password = data_blob(pass, strlen(pass)+1);
675                 }
676                 
677                 p += passlen1 + passlen2;
678                 p += srvstr_pull_buf(inbuf, user, p, sizeof(user), STR_TERMINATE);
679                 p += srvstr_pull_buf(inbuf, domain, p, sizeof(domain), STR_TERMINATE);
680                 p += srvstr_pull_buf(inbuf, native_os, p, sizeof(native_os), STR_TERMINATE);
681                 p += srvstr_pull_buf(inbuf, native_lanman, p, sizeof(native_lanman), STR_TERMINATE);
682                 DEBUG(3,("Domain=[%s]  NativeOS=[%s] NativeLanMan=[%s]\n",
683                          domain,native_os,native_lanman));
684
685                 if ( ra_type == RA_WIN2K )
686                         ra_lanman_string( native_lanman );
687
688         }
689         
690         if (SVAL(inbuf,smb_vwv4) == 0) {
691                 setup_new_vc_session();
692         }
693
694         DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n", domain, user, get_remote_machine_name()));
695
696         if (*user) {
697                 if (global_spnego_negotiated) {
698                         
699                         /* This has to be here, because this is a perfectly valid behaviour for guest logons :-( */
700                         
701                         DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt at 'normal' session setup after negotiating spnego.\n"));
702                         return ERROR_NT(NT_STATUS_UNSUCCESSFUL);
703                 }
704                 fstrcpy(sub_user, user);
705
706                 /* setup the string used by %U */
707                 sub_set_smb_name(user);
708         } else {
709                 fstrcpy(sub_user, lp_guestaccount());
710         }
711
712         sub_set_smb_name(sub_user);
713
714         reload_services(True);
715         
716         if (lp_security() == SEC_SHARE) {
717                 /* in share level we should ignore any passwords */
718
719                 data_blob_free(&lm_resp);
720                 data_blob_free(&nt_resp);
721                 data_blob_clear_free(&plaintext_password);
722
723                 map_username(sub_user);
724                 add_session_user(sub_user);
725                 /* Then force it to null for the benfit of the code below */
726                 *user = 0;
727         }
728         
729         if (!*user) {
730
731                 nt_status = check_guest_password(&server_info);
732
733         } else if (doencrypt) {
734                 if (!negprot_global_auth_context) {
735                         DEBUG(0, ("reply_sesssetup_and_X:  Attempted encrypted session setup without negprot denied!\n"));
736                         return ERROR_NT(NT_STATUS_LOGON_FAILURE);
737                 }
738                 nt_status = make_user_info_for_reply_enc(&user_info, user, domain,
739                                                          lm_resp, nt_resp);
740                 if (NT_STATUS_IS_OK(nt_status)) {
741                         nt_status = negprot_global_auth_context->check_ntlm_password(negprot_global_auth_context, 
742                                                                                      user_info, 
743                                                                                      &server_info);
744                 }
745         } else {
746                 struct auth_context *plaintext_auth_context = NULL;
747                 const uint8 *chal;
748                 if (NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&plaintext_auth_context))) {
749                         chal = plaintext_auth_context->get_ntlm_challenge(plaintext_auth_context);
750                         
751                         if (!make_user_info_for_reply(&user_info, 
752                                                       user, domain, chal,
753                                                       plaintext_password)) {
754                                 nt_status = NT_STATUS_NO_MEMORY;
755                         }
756                 
757                         if (NT_STATUS_IS_OK(nt_status)) {
758                                 nt_status = plaintext_auth_context->check_ntlm_password(plaintext_auth_context, 
759                                                                                         user_info, 
760                                                                                         &server_info); 
761                                 
762                                 (plaintext_auth_context->free)(&plaintext_auth_context);
763                         }
764                 }
765         }
766
767         free_user_info(&user_info);
768         
769         data_blob_free(&lm_resp);
770         data_blob_clear_free(&plaintext_password);
771         
772         if (!NT_STATUS_IS_OK(nt_status)) {
773                 nt_status = do_map_to_guest(nt_status, &server_info, user, domain);
774         }
775         
776         if (!NT_STATUS_IS_OK(nt_status)) {
777                 data_blob_free(&nt_resp);
778                 return ERROR_NT(nt_status_squash(nt_status));
779         }
780
781         /* it's ok - setup a reply */
782         set_message(outbuf,3,0,True);
783         if (Protocol >= PROTOCOL_NT1) {
784                 char *p = smb_buf( outbuf );
785                 p += add_signature( outbuf, p );
786                 set_message_end( outbuf, p );
787                 /* perhaps grab OS version here?? */
788         }
789         
790         if (server_info->guest) {
791                 SSVAL(outbuf,smb_vwv2,1);
792         }
793
794         /* register the name and uid as being validated, so further connections
795            to a uid can get through without a password, on the same VC */
796
797         /* register_vuid keeps the server info */
798         sess_vuid = register_vuid(server_info, nt_resp, sub_user);
799         data_blob_free(&nt_resp);
800
801         if (sess_vuid == -1) {
802                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
803         }
804
805         if (!server_info->guest && !srv_check_sign_mac(inbuf)) {
806                 exit_server("reply_sesssetup_and_X: bad smb signature");
807         }
808
809         SSVAL(outbuf,smb_uid,sess_vuid);
810         SSVAL(inbuf,smb_uid,sess_vuid);
811         
812         if (!done_sesssetup)
813                 max_send = MIN(max_send,smb_bufsize);
814         
815         done_sesssetup = True;
816         
817         END_PROFILE(SMBsesssetupX);
818         return chain_reply(inbuf,outbuf,length,bufsize);
819 }