427caa3ba11d407aef348c7c753477956792f204
[samba.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         asprintf(&user, "%s%s%s", p+1, lp_winbind_separator(), client);
202         
203         pw = Get_Pwnam(user);
204         if (!pw && !foreign) {
205                 pw = Get_Pwnam(client);
206                 SAFE_FREE(user);
207                 user = smb_xstrdup(client);
208         }
209
210         SAFE_FREE(client);
211
212         /* setup the string used by %U */
213         sub_set_smb_name(user);
214
215         reload_services(True);
216
217         if (!pw) {
218                 DEBUG(1,("Username %s is invalid on this system\n",user));
219                 data_blob_free(&ap_rep);
220                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
221         }
222
223         if (!NT_STATUS_IS_OK(ret = make_server_info_pw(&server_info,pw))) {
224                 DEBUG(1,("make_server_info_from_pw failed!\n"));
225                 data_blob_free(&ap_rep);
226                 return ERROR_NT(ret);
227         }
228
229         /* Copy out the session key from the AP_REQ. */
230         memcpy(server_info->session_key, session_key, sizeof(session_key));
231
232         /* register_vuid keeps the server info */
233         sess_vuid = register_vuid(server_info, nullblob, user);
234
235         free(user);
236
237         if (sess_vuid == -1) {
238                 ret = NT_STATUS_LOGON_FAILURE;
239         } else {
240                 set_message(outbuf,4,0,True);
241                 SSVAL(outbuf, smb_vwv3, 0);
242                         
243                 if (server_info->guest) {
244                         SSVAL(outbuf,smb_vwv2,1);
245                 }
246                 
247                 SSVAL(outbuf, smb_uid, sess_vuid);
248
249                 if (!server_info->guest) {
250                         /* We need to start the signing engine
251                          * here but a W2K client sends the old
252                          * "BSRSPYL " signature instead of the
253                          * correct one. Subsequent packets will
254                          * be correct.
255                          */
256                         srv_check_sign_mac(inbuf);
257                 }
258         }
259
260         /* wrap that up in a nice GSS-API wrapping */
261         if (NT_STATUS_IS_OK(ret)) {
262                 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep, TOK_ID_KRB_AP_REP);
263         } else {
264                 ap_rep_wrapped = data_blob(NULL, 0);
265         }
266         response = spnego_gen_auth_response(&ap_rep_wrapped, ret, OID_KERBEROS5_OLD);
267         reply_sesssetup_blob(conn, outbuf, response, ret);
268
269         data_blob_free(&ap_rep);
270         data_blob_free(&ap_rep_wrapped);
271         data_blob_free(&response);
272
273         return -1; /* already replied */
274 }
275 #endif
276
277 /****************************************************************************
278  Send a session setup reply, wrapped in SPNEGO.
279  Get vuid and check first.
280  End the NTLMSSP exchange context if we are OK/complete fail
281 ***************************************************************************/
282
283 static BOOL reply_spnego_ntlmssp(connection_struct *conn, char *inbuf, char *outbuf,
284                                  AUTH_NTLMSSP_STATE **auth_ntlmssp_state,
285                                  DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status) 
286 {
287         BOOL ret;
288         DATA_BLOB response;
289         struct auth_serversupplied_info *server_info = NULL;
290
291         if (NT_STATUS_IS_OK(nt_status)) {
292                 server_info = (*auth_ntlmssp_state)->server_info;
293         } else {
294                 nt_status = do_map_to_guest(nt_status, 
295                                             &server_info, 
296                                             (*auth_ntlmssp_state)->ntlmssp_state->user, 
297                                             (*auth_ntlmssp_state)->ntlmssp_state->domain);
298         }
299
300         if (NT_STATUS_IS_OK(nt_status)) {
301                 int sess_vuid;
302                 DATA_BLOB nullblob = data_blob(NULL, 0);
303
304                 /* register_vuid keeps the server info */
305                 sess_vuid = register_vuid(server_info, nullblob, (*auth_ntlmssp_state)->ntlmssp_state->user);
306                 (*auth_ntlmssp_state)->server_info = NULL;
307
308                 if (sess_vuid == -1) {
309                         nt_status = NT_STATUS_LOGON_FAILURE;
310                 } else {
311                         
312                         set_message(outbuf,4,0,True);
313                         SSVAL(outbuf, smb_vwv3, 0);
314                         
315                         if (server_info->guest) {
316                                 SSVAL(outbuf,smb_vwv2,1);
317                         }
318                         
319                         SSVAL(outbuf,smb_uid,sess_vuid);
320
321                         if (!server_info->guest) {
322                                 /* We need to start the signing engine
323                                  * here but a W2K client sends the old
324                                  * "BSRSPYL " signature instead of the
325                                  * correct one. Subsequent packets will
326                                  * be correct.
327                                  */
328                                 srv_check_sign_mac(inbuf);
329                         }
330                 }
331         }
332
333         response = spnego_gen_auth_response(ntlmssp_blob, nt_status, OID_NTLMSSP);
334         ret = reply_sesssetup_blob(conn, outbuf, response, nt_status);
335         data_blob_free(&response);
336
337         /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
338            and the other end, that we are not finished yet. */
339
340         if (!ret || !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
341                 auth_ntlmssp_end(auth_ntlmssp_state);
342         }
343
344         return ret;
345 }
346
347 /****************************************************************************
348  Reply to a session setup spnego negotiate packet.
349 ****************************************************************************/
350
351 static int reply_spnego_negotiate(connection_struct *conn, 
352                                   char *inbuf,
353                                   char *outbuf,
354                                   int length, int bufsize,
355                                   DATA_BLOB blob1)
356 {
357         char *OIDs[ASN1_MAX_OIDS];
358         DATA_BLOB secblob;
359         int i;
360         DATA_BLOB chal;
361         BOOL got_kerberos = False;
362         NTSTATUS nt_status;
363
364         /* parse out the OIDs and the first sec blob */
365         if (!parse_negTokenTarg(blob1, OIDs, &secblob)) {
366                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
367         }
368
369         /* only look at the first OID for determining the mechToken --
370            accoirding to RFC2478, we should choose the one we want 
371            and renegotiate, but i smell a client bug here..  
372            
373            Problem observed when connecting to a member (samba box) 
374            of an AD domain as a user in a Samba domain.  Samba member 
375            server sent back krb5/mskrb5/ntlmssp as mechtypes, but the 
376            client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an 
377            NTLMSSP mechtoken.                 --jerry              */
378         
379         if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||
380             strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
381                 got_kerberos = True;
382         }
383                 
384         for (i=0;OIDs[i];i++) {
385                 DEBUG(3,("Got OID %s\n", OIDs[i]));
386                 free(OIDs[i]);
387         }
388         DEBUG(3,("Got secblob of size %lu\n", (unsigned long)secblob.length));
389
390 #ifdef HAVE_KRB5
391         if (got_kerberos && (SEC_ADS == lp_security())) {
392                 int ret = reply_spnego_kerberos(conn, inbuf, outbuf, 
393                                                 length, bufsize, &secblob);
394                 data_blob_free(&secblob);
395                 return ret;
396         }
397 #endif
398
399         if (global_ntlmssp_state) {
400                 auth_ntlmssp_end(&global_ntlmssp_state);
401         }
402
403         nt_status = auth_ntlmssp_start(&global_ntlmssp_state);
404         if (!NT_STATUS_IS_OK(nt_status)) {
405                 return ERROR_NT(nt_status);
406         }
407
408         nt_status = auth_ntlmssp_update(global_ntlmssp_state, 
409                                         secblob, &chal);
410
411         data_blob_free(&secblob);
412
413         reply_spnego_ntlmssp(conn, inbuf, outbuf, &global_ntlmssp_state,
414                              &chal, nt_status);
415                 
416         data_blob_free(&chal);
417
418         /* already replied */
419         return -1;
420 }
421         
422 /****************************************************************************
423  Reply to a session setup spnego auth packet.
424 ****************************************************************************/
425
426 static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
427                              int length, int bufsize,
428                              DATA_BLOB blob1)
429 {
430         DATA_BLOB auth, auth_reply;
431         NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
432
433         if (!spnego_parse_auth(blob1, &auth)) {
434 #if 0
435                 file_save("auth.dat", blob1.data, blob1.length);
436 #endif
437                 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
438         }
439         
440         if (!global_ntlmssp_state) {
441                 /* auth before negotiatiate? */
442                 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
443         }
444         
445         nt_status = auth_ntlmssp_update(global_ntlmssp_state, 
446                                                 auth, &auth_reply);
447
448         data_blob_free(&auth);
449
450         reply_spnego_ntlmssp(conn, inbuf, outbuf, &global_ntlmssp_state,
451                              &auth_reply, nt_status);
452                 
453         data_blob_free(&auth_reply);
454
455         /* and tell smbd that we have already replied to this packet */
456         return -1;
457 }
458
459 /****************************************************************************
460  Reply to a session setup command.
461 ****************************************************************************/
462
463 static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,
464                                         char *outbuf,
465                                         int length,int bufsize)
466 {
467         uint8 *p;
468         DATA_BLOB blob1;
469         int ret;
470         size_t bufrem;
471         fstring native_os, native_lanman;
472         char *p2;
473         uint16 data_blob_len = SVAL(inbuf, smb_vwv7);
474         enum remote_arch_types ra_type = get_remote_arch();
475
476         DEBUG(3,("Doing spnego session setup\n"));
477
478         if (global_client_caps == 0) {
479                 global_client_caps = IVAL(inbuf,smb_vwv10);
480         }
481                 
482         p = (uint8 *)smb_buf(inbuf);
483
484         if (data_blob_len == 0) {
485                 /* an invalid request */
486                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
487         }
488
489         bufrem = smb_bufrem(inbuf, p);
490         /* pull the spnego blob */
491         blob1 = data_blob(p, MIN(bufrem, data_blob_len));
492
493 #if 0
494         file_save("negotiate.dat", blob1.data, blob1.length);
495 #endif
496
497         p2 = inbuf + smb_vwv13 + data_blob_len;
498         p2 += srvstr_pull_buf(inbuf, native_os, p2, sizeof(native_os), STR_TERMINATE);
499         p2 += srvstr_pull_buf(inbuf, native_lanman, p2, sizeof(native_lanman), STR_TERMINATE);
500         DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s]\n", native_os, native_lanman));
501
502         if ( ra_type == RA_WIN2K )
503                 ra_lanman_string( native_lanman );
504
505         if (blob1.data[0] == ASN1_APPLICATION(0)) {
506                 /* its a negTokenTarg packet */
507                 ret = reply_spnego_negotiate(conn, inbuf, outbuf, length, bufsize, blob1);
508                 data_blob_free(&blob1);
509                 return ret;
510         }
511
512         if (blob1.data[0] == ASN1_CONTEXT(1)) {
513                 /* its a auth packet */
514                 ret = reply_spnego_auth(conn, inbuf, outbuf, length, bufsize, blob1);
515                 data_blob_free(&blob1);
516                 return ret;
517         }
518
519         /* what sort of packet is this? */
520         DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
521
522         data_blob_free(&blob1);
523
524         return ERROR_NT(NT_STATUS_LOGON_FAILURE);
525 }
526
527 /****************************************************************************
528  On new VC == 0, shutdown *all* old connections and users.
529  It seems that only NT4.x does this. At W2K and above (XP etc.).
530  a new session setup with VC==0 is ignored.
531 ****************************************************************************/
532
533 static void setup_new_vc_session(void)
534 {
535         DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x compatible we would close all old resources.\n"));
536 #if 0
537         conn_close_all();
538         invalidate_all_vuids();
539 #endif
540 }
541
542 /****************************************************************************
543  Reply to a session setup command.
544 ****************************************************************************/
545
546 int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
547                           int length,int bufsize)
548 {
549         int sess_vuid;
550         int   smb_bufsize;    
551         DATA_BLOB lm_resp;
552         DATA_BLOB nt_resp;
553         DATA_BLOB plaintext_password;
554         fstring user;
555         fstring sub_user; /* Sainitised username for substituion */
556         fstring domain;
557         fstring native_os;
558         fstring native_lanman;
559         static BOOL done_sesssetup = False;
560         extern BOOL global_encrypted_passwords_negotiated;
561         extern BOOL global_spnego_negotiated;
562         extern int Protocol;
563         extern int max_send;
564
565         auth_usersupplied_info *user_info = NULL;
566         extern struct auth_context *negprot_global_auth_context;
567         auth_serversupplied_info *server_info = NULL;
568
569         NTSTATUS nt_status;
570
571         BOOL doencrypt = global_encrypted_passwords_negotiated;
572         
573         START_PROFILE(SMBsesssetupX);
574
575         ZERO_STRUCT(lm_resp);
576         ZERO_STRUCT(nt_resp);
577         ZERO_STRUCT(plaintext_password);
578
579         DEBUG(3,("wct=%d flg2=0x%x\n", CVAL(inbuf, smb_wct), SVAL(inbuf, smb_flg2)));
580
581         /* a SPNEGO session setup has 12 command words, whereas a normal
582            NT1 session setup has 13. See the cifs spec. */
583         if (CVAL(inbuf, smb_wct) == 12 &&
584             (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
585                 if (!global_spnego_negotiated) {
586                         DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt at SPNEGO session setup when it was not negoitiated.\n"));
587                         return ERROR_NT(NT_STATUS_UNSUCCESSFUL);
588                 }
589
590                 if (SVAL(inbuf,smb_vwv4) == 0) {
591                         setup_new_vc_session();
592                 }
593                 return reply_sesssetup_and_X_spnego(conn, inbuf, outbuf, length, bufsize);
594         }
595
596         smb_bufsize = SVAL(inbuf,smb_vwv2);
597
598         if (Protocol < PROTOCOL_NT1) {
599                 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
600                 if ((passlen1 > MAX_PASS_LEN) || (passlen1 > smb_bufrem(inbuf, smb_buf(inbuf)))) {
601                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
602                 }
603
604                 if (doencrypt) {
605                         lm_resp = data_blob(smb_buf(inbuf), passlen1);
606                 } else {
607                         plaintext_password = data_blob(smb_buf(inbuf), passlen1+1);
608                         /* Ensure null termination */
609                         plaintext_password.data[passlen1] = 0;
610                 }
611
612                 srvstr_pull_buf(inbuf, user, smb_buf(inbuf)+passlen1, sizeof(user), STR_TERMINATE);
613                 *domain = 0;
614
615         } else {
616                 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
617                 uint16 passlen2 = SVAL(inbuf,smb_vwv8);
618                 enum remote_arch_types ra_type = get_remote_arch();
619                 char *p = smb_buf(inbuf);    
620
621                 if(global_client_caps == 0)
622                         global_client_caps = IVAL(inbuf,smb_vwv11);
623                 
624                 /* client_caps is used as final determination if client is NT or Win95. 
625                    This is needed to return the correct error codes in some
626                    circumstances.
627                 */
628                 
629                 if(ra_type == RA_WINNT || ra_type == RA_WIN2K || ra_type == RA_WIN95) {
630                         if(!(global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))) {
631                                 set_remote_arch( RA_WIN95);
632                         }
633                 }
634
635                 if (!doencrypt) {
636                         /* both Win95 and WinNT stuff up the password lengths for
637                            non-encrypting systems. Uggh. 
638                            
639                            if passlen1==24 its a win95 system, and its setting the
640                            password length incorrectly. Luckily it still works with the
641                            default code because Win95 will null terminate the password
642                            anyway 
643                            
644                            if passlen1>0 and passlen2>0 then maybe its a NT box and its
645                            setting passlen2 to some random value which really stuffs
646                            things up. we need to fix that one.  */
647                         
648                         if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 && passlen2 != 1)
649                                 passlen2 = 0;
650                 }
651                 
652                 /* check for nasty tricks */
653                 if (passlen1 > MAX_PASS_LEN || passlen1 > smb_bufrem(inbuf, p)) {
654                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
655                 }
656
657                 if (passlen2 > MAX_PASS_LEN || passlen2 > smb_bufrem(inbuf, p+passlen1)) {
658                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
659                 }
660
661                 /* Save the lanman2 password and the NT md4 password. */
662                 
663                 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
664                         doencrypt = False;
665                 }
666
667                 if (doencrypt) {
668                         lm_resp = data_blob(p, passlen1);
669                         nt_resp = data_blob(p+passlen1, passlen2);
670                 } else {
671                         pstring pass;
672                         BOOL unic;
673                         unic=SVAL(inbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS;
674                         srvstr_pull(inbuf, pass, smb_buf(inbuf), 
675                                     sizeof(pass),  unic ? passlen2 : passlen1, 
676                                     STR_TERMINATE);
677                         plaintext_password = data_blob(pass, strlen(pass)+1);
678                 }
679                 
680                 p += passlen1 + passlen2;
681                 p += srvstr_pull_buf(inbuf, user, p, sizeof(user), STR_TERMINATE);
682                 p += srvstr_pull_buf(inbuf, domain, p, sizeof(domain), STR_TERMINATE);
683                 p += srvstr_pull_buf(inbuf, native_os, p, sizeof(native_os), STR_TERMINATE);
684                 p += srvstr_pull_buf(inbuf, native_lanman, p, sizeof(native_lanman), STR_TERMINATE);
685                 DEBUG(3,("Domain=[%s]  NativeOS=[%s] NativeLanMan=[%s]\n",
686                          domain,native_os,native_lanman));
687
688                 if ( ra_type == RA_WIN2K )
689                         ra_lanman_string( native_lanman );
690
691         }
692         
693         if (SVAL(inbuf,smb_vwv4) == 0) {
694                 setup_new_vc_session();
695         }
696
697         DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n", domain, user, get_remote_machine_name()));
698
699         if (*user) {
700                 if (global_spnego_negotiated) {
701                         
702                         /* This has to be here, because this is a perfectly valid behaviour for guest logons :-( */
703                         
704                         DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt at 'normal' session setup after negotiating spnego.\n"));
705                         return ERROR_NT(NT_STATUS_UNSUCCESSFUL);
706                 }
707                 fstrcpy(sub_user, user);
708
709                 /* setup the string used by %U */
710                 sub_set_smb_name(user);
711         } else {
712                 fstrcpy(sub_user, lp_guestaccount());
713         }
714
715         sub_set_smb_name(sub_user);
716
717         reload_services(True);
718         
719         if (lp_security() == SEC_SHARE) {
720                 /* in share level we should ignore any passwords */
721
722                 data_blob_free(&lm_resp);
723                 data_blob_free(&nt_resp);
724                 data_blob_clear_free(&plaintext_password);
725
726                 map_username(sub_user);
727                 add_session_user(sub_user);
728                 /* Then force it to null for the benfit of the code below */
729                 *user = 0;
730         }
731         
732         if (!*user) {
733
734                 nt_status = check_guest_password(&server_info);
735
736         } else if (doencrypt) {
737                 if (!negprot_global_auth_context) {
738                         DEBUG(0, ("reply_sesssetup_and_X:  Attempted encrypted session setup without negprot denied!\n"));
739                         return ERROR_NT(NT_STATUS_LOGON_FAILURE);
740                 }
741                 nt_status = make_user_info_for_reply_enc(&user_info, user, domain,
742                                                          lm_resp, nt_resp);
743                 if (NT_STATUS_IS_OK(nt_status)) {
744                         nt_status = negprot_global_auth_context->check_ntlm_password(negprot_global_auth_context, 
745                                                                                      user_info, 
746                                                                                      &server_info);
747                 }
748         } else {
749                 struct auth_context *plaintext_auth_context = NULL;
750                 const uint8 *chal;
751                 if (NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&plaintext_auth_context))) {
752                         chal = plaintext_auth_context->get_ntlm_challenge(plaintext_auth_context);
753                         
754                         if (!make_user_info_for_reply(&user_info, 
755                                                       user, domain, chal,
756                                                       plaintext_password)) {
757                                 nt_status = NT_STATUS_NO_MEMORY;
758                         }
759                 
760                         if (NT_STATUS_IS_OK(nt_status)) {
761                                 nt_status = plaintext_auth_context->check_ntlm_password(plaintext_auth_context, 
762                                                                                         user_info, 
763                                                                                         &server_info); 
764                                 
765                                 (plaintext_auth_context->free)(&plaintext_auth_context);
766                         }
767                 }
768         }
769
770         free_user_info(&user_info);
771         
772         data_blob_free(&lm_resp);
773         data_blob_clear_free(&plaintext_password);
774         
775         if (!NT_STATUS_IS_OK(nt_status)) {
776                 nt_status = do_map_to_guest(nt_status, &server_info, user, domain);
777         }
778         
779         if (!NT_STATUS_IS_OK(nt_status)) {
780                 data_blob_free(&nt_resp);
781                 return ERROR_NT(nt_status_squash(nt_status));
782         }
783
784         /* it's ok - setup a reply */
785         set_message(outbuf,3,0,True);
786         if (Protocol >= PROTOCOL_NT1) {
787                 char *p = smb_buf( outbuf );
788                 p += add_signature( outbuf, p );
789                 set_message_end( outbuf, p );
790                 /* perhaps grab OS version here?? */
791         }
792         
793         if (server_info->guest) {
794                 SSVAL(outbuf,smb_vwv2,1);
795         }
796
797         /* register the name and uid as being validated, so further connections
798            to a uid can get through without a password, on the same VC */
799
800         /* register_vuid keeps the server info */
801         sess_vuid = register_vuid(server_info, nt_resp, sub_user);
802         data_blob_free(&nt_resp);
803
804         if (sess_vuid == -1) {
805                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
806         }
807
808         if (!server_info->guest && !srv_check_sign_mac(inbuf)) {
809                 exit_server("reply_sesssetup_and_X: bad smb signature");
810         }
811
812         SSVAL(outbuf,smb_uid,sess_vuid);
813         SSVAL(inbuf,smb_uid,sess_vuid);
814         
815         if (!done_sesssetup)
816                 max_send = MIN(max_send,smb_bufsize);
817         
818         done_sesssetup = True;
819         
820         END_PROFILE(SMBsesssetupX);
821         return chain_reply(inbuf,outbuf,length,bufsize);
822 }