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