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