Fix for bug #815. Make plaintext unicode passwords work with NT4.x
[tprouty/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         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, primary_domain;
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         p2 += srvstr_pull_buf(inbuf, primary_domain, p2, sizeof(primary_domain), STR_TERMINATE);
501         DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n", 
502                 native_os, native_lanman, primary_domain));
503
504         if ( ra_type == RA_WIN2K ) {
505                 /* Windows 2003 doesn't set the native lanman string, 
506                    but does set primary domain which is a bug I think */
507                            
508                 if ( !strlen(native_lanman) )
509                         ra_lanman_string( primary_domain );
510                 else
511                         ra_lanman_string( native_lanman );
512         }
513                 
514         if (blob1.data[0] == ASN1_APPLICATION(0)) {
515                 /* its a negTokenTarg packet */
516                 ret = reply_spnego_negotiate(conn, inbuf, outbuf, length, bufsize, blob1);
517                 data_blob_free(&blob1);
518                 return ret;
519         }
520
521         if (blob1.data[0] == ASN1_CONTEXT(1)) {
522                 /* its a auth packet */
523                 ret = reply_spnego_auth(conn, inbuf, outbuf, length, bufsize, blob1);
524                 data_blob_free(&blob1);
525                 return ret;
526         }
527
528         /* what sort of packet is this? */
529         DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
530
531         data_blob_free(&blob1);
532
533         return ERROR_NT(NT_STATUS_LOGON_FAILURE);
534 }
535
536 /****************************************************************************
537  On new VC == 0, shutdown *all* old connections and users.
538  It seems that only NT4.x does this. At W2K and above (XP etc.).
539  a new session setup with VC==0 is ignored.
540 ****************************************************************************/
541
542 static void setup_new_vc_session(void)
543 {
544         DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x compatible we would close all old resources.\n"));
545 #if 0
546         conn_close_all();
547         invalidate_all_vuids();
548 #endif
549 }
550
551 /****************************************************************************
552  Reply to a session setup command.
553 ****************************************************************************/
554
555 int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
556                           int length,int bufsize)
557 {
558         int sess_vuid;
559         int   smb_bufsize;    
560         DATA_BLOB lm_resp;
561         DATA_BLOB nt_resp;
562         DATA_BLOB plaintext_password;
563         fstring user;
564         fstring sub_user; /* Sainitised username for substituion */
565         fstring domain;
566         fstring native_os;
567         fstring native_lanman;
568         fstring primary_domain;
569         static BOOL done_sesssetup = False;
570         extern BOOL global_encrypted_passwords_negotiated;
571         extern BOOL global_spnego_negotiated;
572         extern int Protocol;
573         extern int max_send;
574
575         auth_usersupplied_info *user_info = NULL;
576         extern struct auth_context *negprot_global_auth_context;
577         auth_serversupplied_info *server_info = NULL;
578
579         NTSTATUS nt_status;
580
581         BOOL doencrypt = global_encrypted_passwords_negotiated;
582
583         DATA_BLOB session_key;
584         
585         START_PROFILE(SMBsesssetupX);
586
587         ZERO_STRUCT(lm_resp);
588         ZERO_STRUCT(nt_resp);
589         ZERO_STRUCT(plaintext_password);
590
591         DEBUG(3,("wct=%d flg2=0x%x\n", CVAL(inbuf, smb_wct), SVAL(inbuf, smb_flg2)));
592
593         /* a SPNEGO session setup has 12 command words, whereas a normal
594            NT1 session setup has 13. See the cifs spec. */
595         if (CVAL(inbuf, smb_wct) == 12 &&
596             (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
597                 if (!global_spnego_negotiated) {
598                         DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt at SPNEGO session setup when it was not negoitiated.\n"));
599                         return ERROR_NT(NT_STATUS_UNSUCCESSFUL);
600                 }
601
602                 if (SVAL(inbuf,smb_vwv4) == 0) {
603                         setup_new_vc_session();
604                 }
605                 return reply_sesssetup_and_X_spnego(conn, inbuf, outbuf, length, bufsize);
606         }
607
608         smb_bufsize = SVAL(inbuf,smb_vwv2);
609
610         if (Protocol < PROTOCOL_NT1) {
611                 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
612                 if ((passlen1 > MAX_PASS_LEN) || (passlen1 > smb_bufrem(inbuf, smb_buf(inbuf)))) {
613                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
614                 }
615
616                 if (doencrypt) {
617                         lm_resp = data_blob(smb_buf(inbuf), passlen1);
618                 } else {
619                         plaintext_password = data_blob(smb_buf(inbuf), passlen1+1);
620                         /* Ensure null termination */
621                         plaintext_password.data[passlen1] = 0;
622                 }
623
624                 srvstr_pull_buf(inbuf, user, smb_buf(inbuf)+passlen1, sizeof(user), STR_TERMINATE);
625                 *domain = 0;
626
627         } else {
628                 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
629                 uint16 passlen2 = SVAL(inbuf,smb_vwv8);
630                 enum remote_arch_types ra_type = get_remote_arch();
631                 char *p = smb_buf(inbuf);    
632                 char *save_p = smb_buf(inbuf);
633                 uint16 byte_count;
634                         
635
636                 if(global_client_caps == 0) {
637                         global_client_caps = IVAL(inbuf,smb_vwv11);
638                 
639                         if (!(global_client_caps & CAP_STATUS32)) {
640                                 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
641                         }
642
643                         /* client_caps is used as final determination if client is NT or Win95. 
644                            This is needed to return the correct error codes in some
645                            circumstances.
646                         */
647                 
648                         if(ra_type == RA_WINNT || ra_type == RA_WIN2K || ra_type == RA_WIN95) {
649                                 if(!(global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))) {
650                                         set_remote_arch( RA_WIN95);
651                                 }
652                         }
653                 }
654
655                 if (!doencrypt) {
656                         /* both Win95 and WinNT stuff up the password lengths for
657                            non-encrypting systems. Uggh. 
658                            
659                            if passlen1==24 its a win95 system, and its setting the
660                            password length incorrectly. Luckily it still works with the
661                            default code because Win95 will null terminate the password
662                            anyway 
663                            
664                            if passlen1>0 and passlen2>0 then maybe its a NT box and its
665                            setting passlen2 to some random value which really stuffs
666                            things up. we need to fix that one.  */
667                         
668                         if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 && passlen2 != 1)
669                                 passlen2 = 0;
670                 }
671                 
672                 /* check for nasty tricks */
673                 if (passlen1 > MAX_PASS_LEN || passlen1 > smb_bufrem(inbuf, p)) {
674                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
675                 }
676
677                 if (passlen2 > MAX_PASS_LEN || passlen2 > smb_bufrem(inbuf, p+passlen1)) {
678                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
679                 }
680
681                 /* Save the lanman2 password and the NT md4 password. */
682                 
683                 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
684                         doencrypt = False;
685                 }
686
687                 if (doencrypt) {
688                         lm_resp = data_blob(p, passlen1);
689                         nt_resp = data_blob(p+passlen1, passlen2);
690                 } else {
691                         pstring pass;
692                         BOOL unic=SVAL(inbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS;
693
694                         if ((ra_type == RA_WINNT) && (passlen2 == 0) && unic && passlen1) {
695                                 /* NT4.0 stuffs up plaintext unicode password lengths... */
696                                 srvstr_pull(inbuf, pass, smb_buf(inbuf) + 1,
697                                         sizeof(pass), passlen1, STR_TERMINATE);
698                         } else {
699                                 srvstr_pull(inbuf, pass, smb_buf(inbuf), 
700                                         sizeof(pass),  unic ? passlen2 : passlen1, 
701                                         STR_TERMINATE);
702                         }
703                         plaintext_password = data_blob(pass, strlen(pass)+1);
704                 }
705                 
706                 p += passlen1 + passlen2;
707                 p += srvstr_pull_buf(inbuf, user, p, sizeof(user), STR_TERMINATE);
708                 p += srvstr_pull_buf(inbuf, domain, p, sizeof(domain), STR_TERMINATE);
709                 p += srvstr_pull_buf(inbuf, native_os, p, sizeof(native_os), STR_TERMINATE);
710                 p += srvstr_pull_buf(inbuf, native_lanman, p, sizeof(native_lanman), STR_TERMINATE);
711
712                 /* not documented or decoded by Ethereal but there is one more string 
713                    in the extra bytes which is the same as the PrimaryDomain when using 
714                    extended security.  Windows NT 4 and 2003 use this string to store 
715                    the native lanman string. Windows 9x does not include a string here 
716                    at all so we have to check if we have any extra bytes left */
717                 
718                 byte_count = SVAL(inbuf, smb_vwv13);
719                 if ( PTR_DIFF(p, save_p) < byte_count)
720                         p += srvstr_pull_buf(inbuf, primary_domain, p, sizeof(primary_domain), STR_TERMINATE);
721                 else 
722                         fstrcpy( primary_domain, "null" );
723
724                 DEBUG(3,("Domain=[%s]  NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
725                          domain, native_os, native_lanman, primary_domain));
726
727                 if ( ra_type == RA_WIN2K ) {
728                         if ( strlen(native_lanman) == 0 )
729                                 ra_lanman_string( primary_domain );
730                         else
731                                 ra_lanman_string( native_lanman );
732                 }
733
734         }
735
736         if (SVAL(inbuf,smb_vwv4) == 0) {
737                 setup_new_vc_session();
738         }
739
740         DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n", domain, user, get_remote_machine_name()));
741
742         if (*user) {
743                 if (global_spnego_negotiated) {
744                         
745                         /* This has to be here, because this is a perfectly valid behaviour for guest logons :-( */
746                         
747                         DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt at 'normal' session setup after negotiating spnego.\n"));
748                         return ERROR_NT(NT_STATUS_UNSUCCESSFUL);
749                 }
750                 fstrcpy(sub_user, user);
751
752                 /* setup the string used by %U */
753                 sub_set_smb_name(user);
754         } else {
755                 fstrcpy(sub_user, lp_guestaccount());
756         }
757
758         sub_set_smb_name(sub_user);
759
760         reload_services(True);
761         
762         if (lp_security() == SEC_SHARE) {
763                 /* in share level we should ignore any passwords */
764
765                 data_blob_free(&lm_resp);
766                 data_blob_free(&nt_resp);
767                 data_blob_clear_free(&plaintext_password);
768
769                 map_username(sub_user);
770                 add_session_user(sub_user);
771                 /* Then force it to null for the benfit of the code below */
772                 *user = 0;
773         }
774         
775         if (!*user) {
776
777                 nt_status = check_guest_password(&server_info);
778
779         } else if (doencrypt) {
780                 if (!negprot_global_auth_context) {
781                         DEBUG(0, ("reply_sesssetup_and_X:  Attempted encrypted session setup without negprot denied!\n"));
782                         return ERROR_NT(NT_STATUS_LOGON_FAILURE);
783                 }
784                 nt_status = make_user_info_for_reply_enc(&user_info, user, domain,
785                                                          lm_resp, nt_resp);
786                 if (NT_STATUS_IS_OK(nt_status)) {
787                         nt_status = negprot_global_auth_context->check_ntlm_password(negprot_global_auth_context, 
788                                                                                      user_info, 
789                                                                                      &server_info);
790                 }
791         } else {
792                 struct auth_context *plaintext_auth_context = NULL;
793                 const uint8 *chal;
794                 if (NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&plaintext_auth_context))) {
795                         chal = plaintext_auth_context->get_ntlm_challenge(plaintext_auth_context);
796                         
797                         if (!make_user_info_for_reply(&user_info, 
798                                                       user, domain, chal,
799                                                       plaintext_password)) {
800                                 nt_status = NT_STATUS_NO_MEMORY;
801                         }
802                 
803                         if (NT_STATUS_IS_OK(nt_status)) {
804                                 nt_status = plaintext_auth_context->check_ntlm_password(plaintext_auth_context, 
805                                                                                         user_info, 
806                                                                                         &server_info); 
807                                 
808                                 (plaintext_auth_context->free)(&plaintext_auth_context);
809                         }
810                 }
811         }
812
813         free_user_info(&user_info);
814         
815         if (!NT_STATUS_IS_OK(nt_status)) {
816                 nt_status = do_map_to_guest(nt_status, &server_info, user, domain);
817         }
818         
819         if (!NT_STATUS_IS_OK(nt_status)) {
820                 data_blob_free(&nt_resp);
821                 data_blob_free(&lm_resp);
822                 data_blob_clear_free(&plaintext_password);
823                 return ERROR_NT(nt_status_squash(nt_status));
824         }
825
826         if (server_info->nt_session_key.data) {
827                 session_key = data_blob(server_info->nt_session_key.data, server_info->nt_session_key.length);
828         } else if (server_info->lm_session_key.length >= 8 && lm_resp.length == 24) {
829                 session_key = data_blob(NULL, 16);
830                 SMBsesskeygen_lmv1(server_info->lm_session_key.data, lm_resp.data, 
831                                    session_key.data);
832         }
833
834         data_blob_free(&lm_resp);
835         data_blob_clear_free(&plaintext_password);
836         
837         /* it's ok - setup a reply */
838         set_message(outbuf,3,0,True);
839         if (Protocol >= PROTOCOL_NT1) {
840                 char *p = smb_buf( outbuf );
841                 p += add_signature( outbuf, p );
842                 set_message_end( outbuf, p );
843                 /* perhaps grab OS version here?? */
844         }
845         
846         if (server_info->guest) {
847                 SSVAL(outbuf,smb_vwv2,1);
848         }
849
850         /* register the name and uid as being validated, so further connections
851            to a uid can get through without a password, on the same VC */
852
853         /* register_vuid keeps the server info */
854         sess_vuid = register_vuid(server_info, session_key, nt_resp, sub_user);
855         data_blob_free(&nt_resp);
856
857         if (sess_vuid == -1) {
858                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
859         }
860
861         if (!server_info->guest && !srv_check_sign_mac(inbuf)) {
862                 exit_server("reply_sesssetup_and_X: bad smb signature");
863         }
864
865         SSVAL(outbuf,smb_uid,sess_vuid);
866         SSVAL(inbuf,smb_uid,sess_vuid);
867         
868         if (!done_sesssetup)
869                 max_send = MIN(max_send,smb_bufsize);
870         
871         done_sesssetup = True;
872         
873         END_PROFILE(SMBsesssetupX);
874         return chain_reply(inbuf,outbuf,length,bufsize);
875 }