Changes all over the shop, but all towards:
[ira/wip.git] / source3 / smbd / sesssetup.c
1 /* 
2    Unix SMB/CIFS implementation.
3    handle SMBsessionsetup
4    Copyright (C) Andrew Tridgell 1998-2001
5    Copyright (C) Andrew Bartlett      2001
6    Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002
7    Copyright (C) Luke Howard          2003
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25
26 uint32 global_client_caps = 0;
27
28 static struct auth_ntlmssp_state *global_ntlmssp_state;
29
30 /*
31   on a logon error possibly map the error to success if "map to guest"
32   is set approriately
33 */
34 static NTSTATUS do_map_to_guest(NTSTATUS status, auth_serversupplied_info **server_info,
35                                 const char *user, const char *domain)
36 {
37         if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
38                 if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) || 
39                     (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) {
40                         DEBUG(3,("No such user %s [%s] - using guest account\n",
41                                  user, domain));
42                         status = make_server_info_guest(server_info);
43                 }
44         }
45
46         if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
47                 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) {
48                         DEBUG(3,("Registered username %s for guest access\n",user));
49                         status = make_server_info_guest(server_info);
50                 }
51         }
52
53         return status;
54 }
55
56 /****************************************************************************
57  Add the standard 'Samba' signature to the end of the session setup.
58 ****************************************************************************/
59
60 static int add_signature(char *outbuf, char *p)
61 {
62         char *start = p;
63         fstring lanman;
64
65         fstr_sprintf( lanman, "Samba %s", SAMBA_VERSION_STRING);
66
67         p += srvstr_push(outbuf, p, "Unix", -1, STR_TERMINATE);
68         p += srvstr_push(outbuf, p, lanman, -1, STR_TERMINATE);
69         p += srvstr_push(outbuf, p, lp_workgroup(), -1, STR_TERMINATE);
70
71         return PTR_DIFF(p, start);
72 }
73
74 /****************************************************************************
75  Send a security blob via a session setup reply.
76 ****************************************************************************/
77
78 static BOOL reply_sesssetup_blob(connection_struct *conn, char *outbuf,
79                                  DATA_BLOB blob, NTSTATUS nt_status)
80 {
81         char *p;
82
83         set_message(outbuf,4,0,True);
84
85         nt_status = nt_status_squash(nt_status);
86         SIVAL(outbuf, smb_rcls, NT_STATUS_V(nt_status));
87         SSVAL(outbuf, smb_vwv0, 0xFF); /* no chaining possible */
88         SSVAL(outbuf, smb_vwv3, blob.length);
89         p = smb_buf(outbuf);
90
91         /* should we cap this? */
92         memcpy(p, blob.data, blob.length);
93         p += blob.length;
94
95         p += add_signature( outbuf, p );
96
97         set_message_end(outbuf,p);
98
99         return send_smb(smbd_server_fd(),outbuf);
100 }
101
102 /****************************************************************************
103  Do a 'guest' logon, getting back the 
104 ****************************************************************************/
105
106 static NTSTATUS check_guest_password(auth_serversupplied_info **server_info) 
107 {
108         struct auth_context *auth_context;
109         auth_usersupplied_info *user_info = NULL;
110         
111         NTSTATUS nt_status;
112         unsigned char chal[8];
113
114         ZERO_STRUCT(chal);
115
116         DEBUG(3,("Got anonymous request\n"));
117
118         if (!NT_STATUS_IS_OK(nt_status = make_auth_context_fixed(&auth_context, chal))) {
119                 return nt_status;
120         }
121
122         if (!make_user_info_guest(&user_info)) {
123                 (auth_context->free)(&auth_context);
124                 return NT_STATUS_NO_MEMORY;
125         }
126         
127         nt_status = auth_context->check_ntlm_password(auth_context, user_info, server_info);
128         (auth_context->free)(&auth_context);
129         free_user_info(&user_info);
130         return nt_status;
131 }
132
133
134 #ifdef HAVE_KRB5
135 /****************************************************************************
136 reply to a session setup spnego negotiate packet for kerberos
137 ****************************************************************************/
138 static int reply_spnego_kerberos(connection_struct *conn, 
139                                  char *inbuf, char *outbuf,
140                                  int length, int bufsize,
141                                  DATA_BLOB *secblob)
142 {
143         DATA_BLOB ticket;
144         char *client, *p;
145         const struct passwd *pw;
146         char *user;
147         int sess_vuid;
148         NTSTATUS ret;
149         DATA_BLOB auth_data;
150         DATA_BLOB ap_rep, ap_rep_wrapped, response;
151         auth_serversupplied_info *server_info = NULL;
152         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                 
477         p = (uint8 *)smb_buf(inbuf);
478
479         if (data_blob_len == 0) {
480                 /* an invalid request */
481                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
482         }
483
484         bufrem = smb_bufrem(inbuf, p);
485         /* pull the spnego blob */
486         blob1 = data_blob(p, MIN(bufrem, data_blob_len));
487
488 #if 0
489         file_save("negotiate.dat", blob1.data, blob1.length);
490 #endif
491
492         p2 = inbuf + smb_vwv13 + data_blob_len;
493         p2 += srvstr_pull_buf(inbuf, native_os, p2, sizeof(native_os), STR_TERMINATE);
494         p2 += srvstr_pull_buf(inbuf, native_lanman, p2, sizeof(native_lanman), STR_TERMINATE);
495         DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s]\n", native_os, native_lanman));
496
497         if ( ra_type == RA_WIN2K )
498                 ra_lanman_string( native_lanman );
499
500         if (blob1.data[0] == ASN1_APPLICATION(0)) {
501                 /* its a negTokenTarg packet */
502                 ret = reply_spnego_negotiate(conn, inbuf, outbuf, length, bufsize, blob1);
503                 data_blob_free(&blob1);
504                 return ret;
505         }
506
507         if (blob1.data[0] == ASN1_CONTEXT(1)) {
508                 /* its a auth packet */
509                 ret = reply_spnego_auth(conn, inbuf, outbuf, length, bufsize, blob1);
510                 data_blob_free(&blob1);
511                 return ret;
512         }
513
514         /* what sort of packet is this? */
515         DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
516
517         data_blob_free(&blob1);
518
519         return ERROR_NT(NT_STATUS_LOGON_FAILURE);
520 }
521
522 /****************************************************************************
523  On new VC == 0, shutdown *all* old connections and users.
524  It seems that only NT4.x does this. At W2K and above (XP etc.).
525  a new session setup with VC==0 is ignored.
526 ****************************************************************************/
527
528 static void setup_new_vc_session(void)
529 {
530         DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x compatible we would close all old resources.\n"));
531 #if 0
532         conn_close_all();
533         invalidate_all_vuids();
534 #endif
535 }
536
537 /****************************************************************************
538  Reply to a session setup command.
539 ****************************************************************************/
540
541 int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
542                           int length,int bufsize)
543 {
544         int sess_vuid;
545         int   smb_bufsize;    
546         DATA_BLOB lm_resp;
547         DATA_BLOB nt_resp;
548         DATA_BLOB plaintext_password;
549         fstring user;
550         fstring sub_user; /* Sainitised username for substituion */
551         fstring domain;
552         fstring native_os;
553         fstring native_lanman;
554         static BOOL done_sesssetup = False;
555         extern BOOL global_encrypted_passwords_negotiated;
556         extern BOOL global_spnego_negotiated;
557         extern int Protocol;
558         extern int max_send;
559
560         auth_usersupplied_info *user_info = NULL;
561         extern struct auth_context *negprot_global_auth_context;
562         auth_serversupplied_info *server_info = NULL;
563
564         NTSTATUS nt_status;
565
566         BOOL doencrypt = global_encrypted_passwords_negotiated;
567
568         DATA_BLOB session_key;
569         
570         START_PROFILE(SMBsesssetupX);
571
572         ZERO_STRUCT(lm_resp);
573         ZERO_STRUCT(nt_resp);
574         ZERO_STRUCT(plaintext_password);
575
576         DEBUG(3,("wct=%d flg2=0x%x\n", CVAL(inbuf, smb_wct), SVAL(inbuf, smb_flg2)));
577
578         /* a SPNEGO session setup has 12 command words, whereas a normal
579            NT1 session setup has 13. See the cifs spec. */
580         if (CVAL(inbuf, smb_wct) == 12 &&
581             (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
582                 if (!global_spnego_negotiated) {
583                         DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt at SPNEGO session setup when it was not negoitiated.\n"));
584                         return ERROR_NT(NT_STATUS_UNSUCCESSFUL);
585                 }
586
587                 if (SVAL(inbuf,smb_vwv4) == 0) {
588                         setup_new_vc_session();
589                 }
590                 return reply_sesssetup_and_X_spnego(conn, inbuf, outbuf, length, bufsize);
591         }
592
593         smb_bufsize = SVAL(inbuf,smb_vwv2);
594
595         if (Protocol < PROTOCOL_NT1) {
596                 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
597                 if ((passlen1 > MAX_PASS_LEN) || (passlen1 > smb_bufrem(inbuf, smb_buf(inbuf)))) {
598                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
599                 }
600
601                 if (doencrypt) {
602                         lm_resp = data_blob(smb_buf(inbuf), passlen1);
603                 } else {
604                         plaintext_password = data_blob(smb_buf(inbuf), passlen1+1);
605                         /* Ensure null termination */
606                         plaintext_password.data[passlen1] = 0;
607                 }
608
609                 srvstr_pull_buf(inbuf, user, smb_buf(inbuf)+passlen1, sizeof(user), STR_TERMINATE);
610                 *domain = 0;
611
612         } else {
613                 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
614                 uint16 passlen2 = SVAL(inbuf,smb_vwv8);
615                 enum remote_arch_types ra_type = get_remote_arch();
616                 char *p = smb_buf(inbuf);    
617
618                 if(global_client_caps == 0)
619                         global_client_caps = IVAL(inbuf,smb_vwv11);
620                 
621                 /* client_caps is used as final determination if client is NT or Win95. 
622                    This is needed to return the correct error codes in some
623                    circumstances.
624                 */
625                 
626                 if(ra_type == RA_WINNT || ra_type == RA_WIN2K || ra_type == RA_WIN95) {
627                         if(!(global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))) {
628                                 set_remote_arch( RA_WIN95);
629                         }
630                 }
631
632                 if (!doencrypt) {
633                         /* both Win95 and WinNT stuff up the password lengths for
634                            non-encrypting systems. Uggh. 
635                            
636                            if passlen1==24 its a win95 system, and its setting the
637                            password length incorrectly. Luckily it still works with the
638                            default code because Win95 will null terminate the password
639                            anyway 
640                            
641                            if passlen1>0 and passlen2>0 then maybe its a NT box and its
642                            setting passlen2 to some random value which really stuffs
643                            things up. we need to fix that one.  */
644                         
645                         if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 && passlen2 != 1)
646                                 passlen2 = 0;
647                 }
648                 
649                 /* check for nasty tricks */
650                 if (passlen1 > MAX_PASS_LEN || passlen1 > smb_bufrem(inbuf, p)) {
651                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
652                 }
653
654                 if (passlen2 > MAX_PASS_LEN || passlen2 > smb_bufrem(inbuf, p+passlen1)) {
655                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
656                 }
657
658                 /* Save the lanman2 password and the NT md4 password. */
659                 
660                 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
661                         doencrypt = False;
662                 }
663
664                 if (doencrypt) {
665                         lm_resp = data_blob(p, passlen1);
666                         nt_resp = data_blob(p+passlen1, passlen2);
667                 } else {
668                         pstring pass;
669                         BOOL unic;
670                         unic=SVAL(inbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS;
671                         srvstr_pull(inbuf, pass, smb_buf(inbuf), 
672                                     sizeof(pass),  unic ? passlen2 : passlen1, 
673                                     STR_TERMINATE);
674                         plaintext_password = data_blob(pass, strlen(pass)+1);
675                 }
676                 
677                 p += passlen1 + passlen2;
678                 p += srvstr_pull_buf(inbuf, user, p, sizeof(user), STR_TERMINATE);
679                 p += srvstr_pull_buf(inbuf, domain, p, sizeof(domain), STR_TERMINATE);
680                 p += srvstr_pull_buf(inbuf, native_os, p, sizeof(native_os), STR_TERMINATE);
681                 p += srvstr_pull_buf(inbuf, native_lanman, p, sizeof(native_lanman), STR_TERMINATE);
682                 DEBUG(3,("Domain=[%s]  NativeOS=[%s] NativeLanMan=[%s]\n",
683                          domain,native_os,native_lanman));
684
685                 if ( ra_type == RA_WIN2K )
686                         ra_lanman_string( native_lanman );
687
688         }
689         
690         if (SVAL(inbuf,smb_vwv4) == 0) {
691                 setup_new_vc_session();
692         }
693
694         DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n", domain, user, get_remote_machine_name()));
695
696         if (*user) {
697                 if (global_spnego_negotiated) {
698                         
699                         /* This has to be here, because this is a perfectly valid behaviour for guest logons :-( */
700                         
701                         DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt at 'normal' session setup after negotiating spnego.\n"));
702                         return ERROR_NT(NT_STATUS_UNSUCCESSFUL);
703                 }
704                 fstrcpy(sub_user, user);
705
706                 /* setup the string used by %U */
707                 sub_set_smb_name(user);
708         } else {
709                 fstrcpy(sub_user, lp_guestaccount());
710         }
711
712         sub_set_smb_name(sub_user);
713
714         reload_services(True);
715         
716         if (lp_security() == SEC_SHARE) {
717                 /* in share level we should ignore any passwords */
718
719                 data_blob_free(&lm_resp);
720                 data_blob_free(&nt_resp);
721                 data_blob_clear_free(&plaintext_password);
722
723                 map_username(sub_user);
724                 add_session_user(sub_user);
725                 /* Then force it to null for the benfit of the code below */
726                 *user = 0;
727         }
728         
729         if (!*user) {
730
731                 nt_status = check_guest_password(&server_info);
732
733         } else if (doencrypt) {
734                 if (!negprot_global_auth_context) {
735                         DEBUG(0, ("reply_sesssetup_and_X:  Attempted encrypted session setup without negprot denied!\n"));
736                         return ERROR_NT(NT_STATUS_LOGON_FAILURE);
737                 }
738                 nt_status = make_user_info_for_reply_enc(&user_info, user, domain,
739                                                          lm_resp, nt_resp);
740                 if (NT_STATUS_IS_OK(nt_status)) {
741                         nt_status = negprot_global_auth_context->check_ntlm_password(negprot_global_auth_context, 
742                                                                                      user_info, 
743                                                                                      &server_info);
744                 }
745         } else {
746                 struct auth_context *plaintext_auth_context = NULL;
747                 const uint8 *chal;
748                 if (NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&plaintext_auth_context))) {
749                         chal = plaintext_auth_context->get_ntlm_challenge(plaintext_auth_context);
750                         
751                         if (!make_user_info_for_reply(&user_info, 
752                                                       user, domain, chal,
753                                                       plaintext_password)) {
754                                 nt_status = NT_STATUS_NO_MEMORY;
755                         }
756                 
757                         if (NT_STATUS_IS_OK(nt_status)) {
758                                 nt_status = plaintext_auth_context->check_ntlm_password(plaintext_auth_context, 
759                                                                                         user_info, 
760                                                                                         &server_info); 
761                                 
762                                 (plaintext_auth_context->free)(&plaintext_auth_context);
763                         }
764                 }
765         }
766
767         free_user_info(&user_info);
768         
769         if (!NT_STATUS_IS_OK(nt_status)) {
770                 nt_status = do_map_to_guest(nt_status, &server_info, user, domain);
771         }
772         
773         if (!NT_STATUS_IS_OK(nt_status)) {
774                 data_blob_free(&nt_resp);
775                 data_blob_free(&lm_resp);
776                 data_blob_clear_free(&plaintext_password);
777                 return ERROR_NT(nt_status_squash(nt_status));
778         }
779
780         if (server_info->nt_session_key.data) {
781                 session_key = data_blob(server_info->nt_session_key.data, server_info->nt_session_key.length);
782         } else if (server_info->lm_session_key.length >= 8 && lm_resp.length == 24) {
783                 session_key = data_blob(NULL, 16);
784                 SMBsesskeygen_lmv1(server_info->lm_session_key.data, lm_resp.data, 
785                                    session_key.data);
786         }
787
788         data_blob_free(&lm_resp);
789         data_blob_clear_free(&plaintext_password);
790         
791         /* it's ok - setup a reply */
792         set_message(outbuf,3,0,True);
793         if (Protocol >= PROTOCOL_NT1) {
794                 char *p = smb_buf( outbuf );
795                 p += add_signature( outbuf, p );
796                 set_message_end( outbuf, p );
797                 /* perhaps grab OS version here?? */
798         }
799         
800         if (server_info->guest) {
801                 SSVAL(outbuf,smb_vwv2,1);
802         }
803
804         /* register the name and uid as being validated, so further connections
805            to a uid can get through without a password, on the same VC */
806
807         /* register_vuid keeps the server info */
808         sess_vuid = register_vuid(server_info, session_key, nt_resp, sub_user);
809         data_blob_free(&nt_resp);
810
811         if (sess_vuid == -1) {
812                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
813         }
814
815         if (!server_info->guest && !srv_check_sign_mac(inbuf)) {
816                 exit_server("reply_sesssetup_and_X: bad smb signature");
817         }
818
819         SSVAL(outbuf,smb_uid,sess_vuid);
820         SSVAL(inbuf,smb_uid,sess_vuid);
821         
822         if (!done_sesssetup)
823                 max_send = MIN(max_send,smb_bufsize);
824         
825         done_sesssetup = True;
826         
827         END_PROFILE(SMBsesssetupX);
828         return chain_reply(inbuf,outbuf,length,bufsize);
829 }