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