0122b662ebfabb7f0ed223b6919f879652ab5157
[tprouty/samba.git] / source / smbd / sesssetup.c
1 /* 
2    Unix SMB/CIFS implementation.
3    handle SMBsessionsetup
4    Copyright (C) Andrew Tridgell 1998-2001
5    Copyright (C) Andrew Bartlett      2001
6    Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002
7    Copyright (C) Luke Howard          2003
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25
26 uint32 global_client_caps = 0;
27
28 static struct auth_ntlmssp_state *global_ntlmssp_state;
29
30 /*
31   on a logon error possibly map the error to success if "map to guest"
32   is set approriately
33 */
34 static NTSTATUS do_map_to_guest(NTSTATUS status, auth_serversupplied_info **server_info,
35                                 const char *user, const char *domain)
36 {
37         if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
38                 if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) || 
39                     (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) {
40                         DEBUG(3,("No such user %s [%s] - using guest account\n",
41                                  user, domain));
42                         status = make_server_info_guest(server_info);
43                 }
44         }
45
46         if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
47                 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) {
48                         DEBUG(3,("Registered username %s for guest access\n",user));
49                         status = make_server_info_guest(server_info);
50                 }
51         }
52
53         return status;
54 }
55
56 /****************************************************************************
57  Add the standard 'Samba' signature to the end of the session setup.
58 ****************************************************************************/
59
60 static int add_signature(char *outbuf, char *p)
61 {
62         char *start = p;
63         fstring lanman;
64
65         fstr_sprintf( lanman, "Samba %s", SAMBA_VERSION_STRING);
66
67         p += srvstr_push(outbuf, p, "Unix", -1, STR_TERMINATE);
68         p += srvstr_push(outbuf, p, lanman, -1, STR_TERMINATE);
69         p += srvstr_push(outbuf, p, lp_workgroup(), -1, STR_TERMINATE);
70
71         return PTR_DIFF(p, start);
72 }
73
74 /****************************************************************************
75  Send a security blob via a session setup reply.
76 ****************************************************************************/
77
78 static BOOL reply_sesssetup_blob(connection_struct *conn, char *outbuf,
79                                  DATA_BLOB blob, NTSTATUS nt_status)
80 {
81         char *p;
82
83         set_message(outbuf,4,0,True);
84
85         nt_status = nt_status_squash(nt_status);
86         SIVAL(outbuf, smb_rcls, NT_STATUS_V(nt_status));
87         SSVAL(outbuf, smb_vwv0, 0xFF); /* no chaining possible */
88         SSVAL(outbuf, smb_vwv3, blob.length);
89         p = smb_buf(outbuf);
90
91         /* should we cap this? */
92         memcpy(p, blob.data, blob.length);
93         p += blob.length;
94
95         p += add_signature( outbuf, p );
96
97         set_message_end(outbuf,p);
98
99         return send_smb(smbd_server_fd(),outbuf);
100 }
101
102 /****************************************************************************
103  Do a 'guest' logon, getting back the 
104 ****************************************************************************/
105
106 static NTSTATUS check_guest_password(auth_serversupplied_info **server_info) 
107 {
108         struct auth_context *auth_context;
109         auth_usersupplied_info *user_info = NULL;
110         
111         NTSTATUS nt_status;
112         unsigned char chal[8];
113
114         ZERO_STRUCT(chal);
115
116         DEBUG(3,("Got anonymous request\n"));
117
118         if (!NT_STATUS_IS_OK(nt_status = make_auth_context_fixed(&auth_context, chal))) {
119                 return nt_status;
120         }
121
122         if (!make_user_info_guest(&user_info)) {
123                 (auth_context->free)(&auth_context);
124                 return NT_STATUS_NO_MEMORY;
125         }
126         
127         nt_status = auth_context->check_ntlm_password(auth_context, user_info, server_info);
128         (auth_context->free)(&auth_context);
129         free_user_info(&user_info);
130         return nt_status;
131 }
132
133
134 #ifdef HAVE_KRB5
135 /****************************************************************************
136 reply to a session setup spnego negotiate packet for kerberos
137 ****************************************************************************/
138 static int reply_spnego_kerberos(connection_struct *conn, 
139                                  char *inbuf, char *outbuf,
140                                  int length, int bufsize,
141                                  DATA_BLOB *secblob)
142 {
143         DATA_BLOB ticket;
144         char *client, *p, *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 = data_blob(NULL, 0);
154         uint8 tok_id[2];
155         DATA_BLOB nullblob = data_blob(NULL, 0);
156         fstring real_username;
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         ret = ads_verify_ticket(lp_realm(), &ticket, &client, &auth_data, &ap_rep, &session_key);
169
170         data_blob_free(&ticket);
171
172         if (!NT_STATUS_IS_OK(ret)) {
173                 DEBUG(1,("Failed to verify incoming ticket!\n"));       
174                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
175         }
176
177         data_blob_free(&auth_data);
178
179         DEBUG(3,("Ticket name is [%s]\n", client));
180
181         p = strchr_m(client, '@');
182         if (!p) {
183                 DEBUG(3,("Doesn't look like a valid principal\n"));
184                 data_blob_free(&ap_rep);
185                 data_blob_free(&session_key);
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                         data_blob_free(&session_key);
196                         SAFE_FREE(client);
197                         return ERROR_NT(NT_STATUS_LOGON_FAILURE);
198                 }
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         map_username( user );
246
247         pw = smb_getpwnam( user, real_username, True );
248         
249         if (!pw) {
250                 DEBUG(1,("Username %s is invalid on this system\n",user));
251                 SAFE_FREE(user);
252                 SAFE_FREE(client);
253                 data_blob_free(&ap_rep);
254                 data_blob_free(&session_key);
255                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
256         }
257
258         /* setup the string used by %U */
259         
260         sub_set_smb_name( real_username );
261         reload_services(True);
262         
263         if (!NT_STATUS_IS_OK(ret = make_server_info_pw(&server_info, real_username, pw))) 
264         {
265                 DEBUG(1,("make_server_info_from_pw failed!\n"));
266                 SAFE_FREE(user);
267                 SAFE_FREE(client);
268                 data_blob_free(&ap_rep);
269                 data_blob_free(&session_key);
270                 return ERROR_NT(ret);
271         }
272
273         /* make_server_info_pw does not set the domain. Without this we end up
274          * with the local netbios name in substitutions for %D. */
275
276         if (server_info->sam_account != NULL) {
277                 pdb_set_domain(server_info->sam_account, domain, PDB_SET);
278         }
279
280         /* register_vuid keeps the server info */
281         /* register_vuid takes ownership of session_key, no need to free after this.
282            A better interface would copy it.... */
283         sess_vuid = register_vuid(server_info, session_key, nullblob, client);
284
285         SAFE_FREE(user);
286         SAFE_FREE(client);
287
288         if (sess_vuid == -1) {
289                 ret = NT_STATUS_LOGON_FAILURE;
290         } else {
291                 /* current_user_info is changed on new vuid */
292                 reload_services( True );
293
294                 set_message(outbuf,4,0,True);
295                 SSVAL(outbuf, smb_vwv3, 0);
296                         
297                 if (server_info->guest) {
298                         SSVAL(outbuf,smb_vwv2,1);
299                 }
300                 
301                 SSVAL(outbuf, smb_uid, sess_vuid);
302
303                 if (!server_info->guest && !srv_signing_started()) {
304                         /* We need to start the signing engine
305                          * here but a W2K client sends the old
306                          * "BSRSPYL " signature instead of the
307                          * correct one. Subsequent packets will
308                          * be correct.
309                          */
310                         srv_check_sign_mac(inbuf, False);
311                 }
312         }
313
314         /* wrap that up in a nice GSS-API wrapping */
315         if (NT_STATUS_IS_OK(ret)) {
316                 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep, TOK_ID_KRB_AP_REP);
317         } else {
318                 ap_rep_wrapped = data_blob(NULL, 0);
319         }
320         response = spnego_gen_auth_response(&ap_rep_wrapped, ret, OID_KERBEROS5_OLD);
321         reply_sesssetup_blob(conn, outbuf, response, ret);
322
323         data_blob_free(&ap_rep);
324         data_blob_free(&ap_rep_wrapped);
325         data_blob_free(&response);
326
327         return -1; /* already replied */
328 }
329 #endif
330
331 /****************************************************************************
332  Send a session setup reply, wrapped in SPNEGO.
333  Get vuid and check first.
334  End the NTLMSSP exchange context if we are OK/complete fail
335 ***************************************************************************/
336
337 static BOOL reply_spnego_ntlmssp(connection_struct *conn, char *inbuf, char *outbuf,
338                                  AUTH_NTLMSSP_STATE **auth_ntlmssp_state,
339                                  DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status) 
340 {
341         BOOL ret;
342         DATA_BLOB response;
343         struct auth_serversupplied_info *server_info = NULL;
344
345         if (NT_STATUS_IS_OK(nt_status)) {
346                 server_info = (*auth_ntlmssp_state)->server_info;
347         } else {
348                 nt_status = do_map_to_guest(nt_status, 
349                                             &server_info, 
350                                             (*auth_ntlmssp_state)->ntlmssp_state->user, 
351                                             (*auth_ntlmssp_state)->ntlmssp_state->domain);
352         }
353
354         if (NT_STATUS_IS_OK(nt_status)) {
355                 int sess_vuid;
356                 DATA_BLOB nullblob = data_blob(NULL, 0);
357                 DATA_BLOB session_key = data_blob((*auth_ntlmssp_state)->ntlmssp_state->session_key.data, (*auth_ntlmssp_state)->ntlmssp_state->session_key.length);
358
359                 /* register_vuid keeps the server info */
360                 sess_vuid = register_vuid(server_info, session_key, nullblob, (*auth_ntlmssp_state)->ntlmssp_state->user);
361                 (*auth_ntlmssp_state)->server_info = NULL;
362
363                 if (sess_vuid == -1) {
364                         nt_status = NT_STATUS_LOGON_FAILURE;
365                 } else {
366                         
367                         /* current_user_info is changed on new vuid */
368                         reload_services( True );
369
370                         set_message(outbuf,4,0,True);
371                         SSVAL(outbuf, smb_vwv3, 0);
372                         
373                         if (server_info->guest) {
374                                 SSVAL(outbuf,smb_vwv2,1);
375                         }
376                         
377                         SSVAL(outbuf,smb_uid,sess_vuid);
378
379                         if (!server_info->guest && !srv_signing_started()) {
380                                 /* We need to start the signing engine
381                                  * here but a W2K client sends the old
382                                  * "BSRSPYL " signature instead of the
383                                  * correct one. Subsequent packets will
384                                  * be correct.
385                                  */
386
387                                 srv_check_sign_mac(inbuf, False);
388                         }
389                 }
390         }
391
392         response = spnego_gen_auth_response(ntlmssp_blob, nt_status, OID_NTLMSSP);
393         ret = reply_sesssetup_blob(conn, outbuf, response, nt_status);
394         data_blob_free(&response);
395
396         /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
397            and the other end, that we are not finished yet. */
398
399         if (!ret || !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
400                 auth_ntlmssp_end(auth_ntlmssp_state);
401         }
402
403         return ret;
404 }
405
406 /****************************************************************************
407  Reply to a session setup spnego negotiate packet.
408 ****************************************************************************/
409
410 static int reply_spnego_negotiate(connection_struct *conn, 
411                                   char *inbuf,
412                                   char *outbuf,
413                                   int length, int bufsize,
414                                   DATA_BLOB blob1)
415 {
416         char *OIDs[ASN1_MAX_OIDS];
417         DATA_BLOB secblob;
418         int i;
419         DATA_BLOB chal;
420         BOOL got_kerberos = False;
421         NTSTATUS nt_status;
422
423         /* parse out the OIDs and the first sec blob */
424         if (!parse_negTokenTarg(blob1, OIDs, &secblob)) {
425                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
426         }
427
428         /* only look at the first OID for determining the mechToken --
429            accoirding to RFC2478, we should choose the one we want 
430            and renegotiate, but i smell a client bug here..  
431            
432            Problem observed when connecting to a member (samba box) 
433            of an AD domain as a user in a Samba domain.  Samba member 
434            server sent back krb5/mskrb5/ntlmssp as mechtypes, but the 
435            client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an 
436            NTLMSSP mechtoken.                 --jerry              */
437         
438         if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||
439             strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
440                 got_kerberos = True;
441         }
442                 
443         for (i=0;OIDs[i];i++) {
444                 DEBUG(3,("Got OID %s\n", OIDs[i]));
445                 free(OIDs[i]);
446         }
447         DEBUG(3,("Got secblob of size %lu\n", (unsigned long)secblob.length));
448
449 #ifdef HAVE_KRB5
450         if (got_kerberos && (SEC_ADS == lp_security())) {
451                 int ret = reply_spnego_kerberos(conn, inbuf, outbuf, 
452                                                 length, bufsize, &secblob);
453                 data_blob_free(&secblob);
454                 return ret;
455         }
456 #endif
457
458         if (global_ntlmssp_state) {
459                 auth_ntlmssp_end(&global_ntlmssp_state);
460         }
461
462         nt_status = auth_ntlmssp_start(&global_ntlmssp_state);
463         if (!NT_STATUS_IS_OK(nt_status)) {
464                 return ERROR_NT(nt_status);
465         }
466
467         nt_status = auth_ntlmssp_update(global_ntlmssp_state, 
468                                         secblob, &chal);
469
470         data_blob_free(&secblob);
471
472         reply_spnego_ntlmssp(conn, inbuf, outbuf, &global_ntlmssp_state,
473                              &chal, nt_status);
474                 
475         data_blob_free(&chal);
476
477         /* already replied */
478         return -1;
479 }
480         
481 /****************************************************************************
482  Reply to a session setup spnego auth packet.
483 ****************************************************************************/
484
485 static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
486                              int length, int bufsize,
487                              DATA_BLOB blob1)
488 {
489         DATA_BLOB auth, auth_reply;
490         NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
491
492         if (!spnego_parse_auth(blob1, &auth)) {
493 #if 0
494                 file_save("auth.dat", blob1.data, blob1.length);
495 #endif
496                 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
497         }
498         
499         if (!global_ntlmssp_state) {
500                 /* auth before negotiatiate? */
501                 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
502         }
503         
504         nt_status = auth_ntlmssp_update(global_ntlmssp_state, 
505                                                 auth, &auth_reply);
506
507         data_blob_free(&auth);
508
509         reply_spnego_ntlmssp(conn, inbuf, outbuf, &global_ntlmssp_state,
510                              &auth_reply, nt_status);
511                 
512         data_blob_free(&auth_reply);
513
514         /* and tell smbd that we have already replied to this packet */
515         return -1;
516 }
517
518 /****************************************************************************
519  Reply to a session setup command.
520 ****************************************************************************/
521
522 static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,
523                                         char *outbuf,
524                                         int length,int bufsize)
525 {
526         uint8 *p;
527         DATA_BLOB blob1;
528         int ret;
529         size_t bufrem;
530         fstring native_os, native_lanman, primary_domain;
531         char *p2;
532         uint16 data_blob_len = SVAL(inbuf, smb_vwv7);
533         enum remote_arch_types ra_type = get_remote_arch();
534
535         DEBUG(3,("Doing spnego session setup\n"));
536
537         if (global_client_caps == 0) {
538                 global_client_caps = IVAL(inbuf,smb_vwv10);
539
540                 if (!(global_client_caps & CAP_STATUS32)) {
541                         remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
542                 }
543
544         }
545                 
546         p = (uint8 *)smb_buf(inbuf);
547
548         if (data_blob_len == 0) {
549                 /* an invalid request */
550                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
551         }
552
553         bufrem = smb_bufrem(inbuf, p);
554         /* pull the spnego blob */
555         blob1 = data_blob(p, MIN(bufrem, data_blob_len));
556
557 #if 0
558         file_save("negotiate.dat", blob1.data, blob1.length);
559 #endif
560
561         p2 = inbuf + smb_vwv13 + data_blob_len;
562         p2 += srvstr_pull_buf(inbuf, native_os, p2, sizeof(native_os), STR_TERMINATE);
563         p2 += srvstr_pull_buf(inbuf, native_lanman, p2, sizeof(native_lanman), STR_TERMINATE);
564         p2 += srvstr_pull_buf(inbuf, primary_domain, p2, sizeof(primary_domain), STR_TERMINATE);
565         DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n", 
566                 native_os, native_lanman, primary_domain));
567
568         if ( ra_type == RA_WIN2K ) {
569                 /* Windows 2003 doesn't set the native lanman string, 
570                    but does set primary domain which is a bug I think */
571                            
572                 if ( !strlen(native_lanman) )
573                         ra_lanman_string( primary_domain );
574                 else
575                         ra_lanman_string( native_lanman );
576         }
577                 
578         if (blob1.data[0] == ASN1_APPLICATION(0)) {
579                 /* its a negTokenTarg packet */
580                 ret = reply_spnego_negotiate(conn, inbuf, outbuf, length, bufsize, blob1);
581                 data_blob_free(&blob1);
582                 return ret;
583         }
584
585         if (blob1.data[0] == ASN1_CONTEXT(1)) {
586                 /* its a auth packet */
587                 ret = reply_spnego_auth(conn, inbuf, outbuf, length, bufsize, blob1);
588                 data_blob_free(&blob1);
589                 return ret;
590         }
591
592         /* what sort of packet is this? */
593         DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
594
595         data_blob_free(&blob1);
596
597         return ERROR_NT(NT_STATUS_LOGON_FAILURE);
598 }
599
600 /****************************************************************************
601  On new VC == 0, shutdown *all* old connections and users.
602  It seems that only NT4.x does this. At W2K and above (XP etc.).
603  a new session setup with VC==0 is ignored.
604 ****************************************************************************/
605
606 static void setup_new_vc_session(void)
607 {
608         DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x compatible we would close all old resources.\n"));
609 #if 0
610         conn_close_all();
611         invalidate_all_vuids();
612 #endif
613 }
614
615 /****************************************************************************
616  Reply to a session setup command.
617 ****************************************************************************/
618
619 int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
620                           int length,int bufsize)
621 {
622         int sess_vuid;
623         int   smb_bufsize;    
624         DATA_BLOB lm_resp;
625         DATA_BLOB nt_resp;
626         DATA_BLOB plaintext_password;
627         fstring user;
628         fstring sub_user; /* Sainitised username for substituion */
629         fstring domain;
630         fstring native_os;
631         fstring native_lanman;
632         fstring primary_domain;
633         static BOOL done_sesssetup = False;
634         extern BOOL global_encrypted_passwords_negotiated;
635         extern BOOL global_spnego_negotiated;
636         extern int Protocol;
637         extern int max_send;
638
639         auth_usersupplied_info *user_info = NULL;
640         extern struct auth_context *negprot_global_auth_context;
641         auth_serversupplied_info *server_info = NULL;
642
643         NTSTATUS nt_status;
644
645         BOOL doencrypt = global_encrypted_passwords_negotiated;
646
647         DATA_BLOB session_key;
648         
649         START_PROFILE(SMBsesssetupX);
650
651         ZERO_STRUCT(lm_resp);
652         ZERO_STRUCT(nt_resp);
653         ZERO_STRUCT(plaintext_password);
654
655         DEBUG(3,("wct=%d flg2=0x%x\n", CVAL(inbuf, smb_wct), SVAL(inbuf, smb_flg2)));
656
657         /* a SPNEGO session setup has 12 command words, whereas a normal
658            NT1 session setup has 13. See the cifs spec. */
659         if (CVAL(inbuf, smb_wct) == 12 &&
660             (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
661                 if (!global_spnego_negotiated) {
662                         DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt at SPNEGO session setup when it was not negoitiated.\n"));
663                         return ERROR_NT(NT_STATUS_UNSUCCESSFUL);
664                 }
665
666                 if (SVAL(inbuf,smb_vwv4) == 0) {
667                         setup_new_vc_session();
668                 }
669                 return reply_sesssetup_and_X_spnego(conn, inbuf, outbuf, length, bufsize);
670         }
671
672         smb_bufsize = SVAL(inbuf,smb_vwv2);
673
674         if (Protocol < PROTOCOL_NT1) {
675                 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
676                 if ((passlen1 > MAX_PASS_LEN) || (passlen1 > smb_bufrem(inbuf, smb_buf(inbuf)))) {
677                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
678                 }
679
680                 if (doencrypt) {
681                         lm_resp = data_blob(smb_buf(inbuf), passlen1);
682                 } else {
683                         plaintext_password = data_blob(smb_buf(inbuf), passlen1+1);
684                         /* Ensure null termination */
685                         plaintext_password.data[passlen1] = 0;
686                 }
687
688                 srvstr_pull_buf(inbuf, user, smb_buf(inbuf)+passlen1, sizeof(user), STR_TERMINATE);
689                 *domain = 0;
690
691         } else {
692                 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
693                 uint16 passlen2 = SVAL(inbuf,smb_vwv8);
694                 enum remote_arch_types ra_type = get_remote_arch();
695                 char *p = smb_buf(inbuf);    
696                 char *save_p = smb_buf(inbuf);
697                 uint16 byte_count;
698                         
699
700                 if(global_client_caps == 0) {
701                         global_client_caps = IVAL(inbuf,smb_vwv11);
702                 
703                         if (!(global_client_caps & CAP_STATUS32)) {
704                                 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
705                         }
706
707                         /* client_caps is used as final determination if client is NT or Win95. 
708                            This is needed to return the correct error codes in some
709                            circumstances.
710                         */
711                 
712                         if(ra_type == RA_WINNT || ra_type == RA_WIN2K || ra_type == RA_WIN95) {
713                                 if(!(global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))) {
714                                         set_remote_arch( RA_WIN95);
715                                 }
716                         }
717                 }
718
719                 if (!doencrypt) {
720                         /* both Win95 and WinNT stuff up the password lengths for
721                            non-encrypting systems. Uggh. 
722                            
723                            if passlen1==24 its a win95 system, and its setting the
724                            password length incorrectly. Luckily it still works with the
725                            default code because Win95 will null terminate the password
726                            anyway 
727                            
728                            if passlen1>0 and passlen2>0 then maybe its a NT box and its
729                            setting passlen2 to some random value which really stuffs
730                            things up. we need to fix that one.  */
731                         
732                         if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 && passlen2 != 1)
733                                 passlen2 = 0;
734                 }
735                 
736                 /* check for nasty tricks */
737                 if (passlen1 > MAX_PASS_LEN || passlen1 > smb_bufrem(inbuf, p)) {
738                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
739                 }
740
741                 if (passlen2 > MAX_PASS_LEN || passlen2 > smb_bufrem(inbuf, p+passlen1)) {
742                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
743                 }
744
745                 /* Save the lanman2 password and the NT md4 password. */
746                 
747                 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
748                         doencrypt = False;
749                 }
750
751                 if (doencrypt) {
752                         lm_resp = data_blob(p, passlen1);
753                         nt_resp = data_blob(p+passlen1, passlen2);
754                 } else {
755                         pstring pass;
756                         BOOL unic=SVAL(inbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS;
757
758                         if ((ra_type == RA_WINNT) && (passlen2 == 0) && unic && passlen1) {
759                                 /* NT4.0 stuffs up plaintext unicode password lengths... */
760                                 srvstr_pull(inbuf, pass, smb_buf(inbuf) + 1,
761                                         sizeof(pass), passlen1, STR_TERMINATE);
762                         } else {
763                                 srvstr_pull(inbuf, pass, smb_buf(inbuf), 
764                                         sizeof(pass),  unic ? passlen2 : passlen1, 
765                                         STR_TERMINATE);
766                         }
767                         plaintext_password = data_blob(pass, strlen(pass)+1);
768                 }
769                 
770                 p += passlen1 + passlen2;
771                 p += srvstr_pull_buf(inbuf, user, p, sizeof(user), STR_TERMINATE);
772                 p += srvstr_pull_buf(inbuf, domain, p, sizeof(domain), STR_TERMINATE);
773                 p += srvstr_pull_buf(inbuf, native_os, p, sizeof(native_os), STR_TERMINATE);
774                 p += srvstr_pull_buf(inbuf, native_lanman, p, sizeof(native_lanman), STR_TERMINATE);
775
776                 /* not documented or decoded by Ethereal but there is one more string 
777                    in the extra bytes which is the same as the PrimaryDomain when using 
778                    extended security.  Windows NT 4 and 2003 use this string to store 
779                    the native lanman string. Windows 9x does not include a string here 
780                    at all so we have to check if we have any extra bytes left */
781                 
782                 byte_count = SVAL(inbuf, smb_vwv13);
783                 if ( PTR_DIFF(p, save_p) < byte_count)
784                         p += srvstr_pull_buf(inbuf, primary_domain, p, sizeof(primary_domain), STR_TERMINATE);
785                 else 
786                         fstrcpy( primary_domain, "null" );
787
788                 DEBUG(3,("Domain=[%s]  NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
789                          domain, native_os, native_lanman, primary_domain));
790
791                 if ( ra_type == RA_WIN2K ) {
792                         if ( strlen(native_lanman) == 0 )
793                                 ra_lanman_string( primary_domain );
794                         else
795                                 ra_lanman_string( native_lanman );
796                 }
797
798         }
799
800         if (SVAL(inbuf,smb_vwv4) == 0) {
801                 setup_new_vc_session();
802         }
803
804         DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n", domain, user, get_remote_machine_name()));
805
806         if (*user) {
807                 if (global_spnego_negotiated) {
808                         
809                         /* This has to be here, because this is a perfectly valid behaviour for guest logons :-( */
810                         
811                         DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt at 'normal' session setup after negotiating spnego.\n"));
812                         return ERROR_NT(NT_STATUS_UNSUCCESSFUL);
813                 }
814                 fstrcpy(sub_user, user);
815
816                 /* setup the string used by %U */
817                 sub_set_smb_name(user);
818         } else {
819                 fstrcpy(sub_user, lp_guestaccount());
820         }
821
822         sub_set_smb_name(sub_user);
823
824         reload_services(True);
825         
826         if (lp_security() == SEC_SHARE) {
827                 /* in share level we should ignore any passwords */
828
829                 data_blob_free(&lm_resp);
830                 data_blob_free(&nt_resp);
831                 data_blob_clear_free(&plaintext_password);
832
833                 map_username(sub_user);
834                 add_session_user(sub_user);
835                 /* Then force it to null for the benfit of the code below */
836                 *user = 0;
837         }
838         
839         if (!*user) {
840
841                 nt_status = check_guest_password(&server_info);
842
843         } else if (doencrypt) {
844                 if (!negprot_global_auth_context) {
845                         DEBUG(0, ("reply_sesssetup_and_X:  Attempted encrypted session setup without negprot denied!\n"));
846                         return ERROR_NT(NT_STATUS_LOGON_FAILURE);
847                 }
848                 nt_status = make_user_info_for_reply_enc(&user_info, user, domain,
849                                                          lm_resp, nt_resp);
850                 if (NT_STATUS_IS_OK(nt_status)) {
851                         nt_status = negprot_global_auth_context->check_ntlm_password(negprot_global_auth_context, 
852                                                                                      user_info, 
853                                                                                      &server_info);
854                 }
855         } else {
856                 struct auth_context *plaintext_auth_context = NULL;
857                 const uint8 *chal;
858                 if (NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&plaintext_auth_context))) {
859                         chal = plaintext_auth_context->get_ntlm_challenge(plaintext_auth_context);
860                         
861                         if (!make_user_info_for_reply(&user_info, 
862                                                       user, domain, chal,
863                                                       plaintext_password)) {
864                                 nt_status = NT_STATUS_NO_MEMORY;
865                         }
866                 
867                         if (NT_STATUS_IS_OK(nt_status)) {
868                                 nt_status = plaintext_auth_context->check_ntlm_password(plaintext_auth_context, 
869                                                                                         user_info, 
870                                                                                         &server_info); 
871                                 
872                                 (plaintext_auth_context->free)(&plaintext_auth_context);
873                         }
874                 }
875         }
876
877         free_user_info(&user_info);
878         
879         if (!NT_STATUS_IS_OK(nt_status)) {
880                 nt_status = do_map_to_guest(nt_status, &server_info, user, domain);
881         }
882         
883         if (!NT_STATUS_IS_OK(nt_status)) {
884                 data_blob_free(&nt_resp);
885                 data_blob_free(&lm_resp);
886                 data_blob_clear_free(&plaintext_password);
887                 return ERROR_NT(nt_status_squash(nt_status));
888         }
889
890         if (server_info->user_session_key.data) {
891                 session_key = data_blob(server_info->user_session_key.data, server_info->user_session_key.length);
892         } else {
893                 session_key = data_blob(NULL, 0);
894         }
895
896         data_blob_clear_free(&plaintext_password);
897         
898         /* it's ok - setup a reply */
899         set_message(outbuf,3,0,True);
900         if (Protocol >= PROTOCOL_NT1) {
901                 char *p = smb_buf( outbuf );
902                 p += add_signature( outbuf, p );
903                 set_message_end( outbuf, p );
904                 /* perhaps grab OS version here?? */
905         }
906         
907         if (server_info->guest) {
908                 SSVAL(outbuf,smb_vwv2,1);
909         }
910
911         /* register the name and uid as being validated, so further connections
912            to a uid can get through without a password, on the same VC */
913
914         /* register_vuid keeps the server info */
915         sess_vuid = register_vuid(server_info, session_key, nt_resp.data ? nt_resp : lm_resp, sub_user);
916         data_blob_free(&nt_resp);
917         data_blob_free(&lm_resp);
918
919         if (sess_vuid == -1) {
920                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
921         }
922
923         /* current_user_info is changed on new vuid */
924         reload_services( True );
925
926         if (!server_info->guest && !srv_signing_started() && !srv_check_sign_mac(inbuf, True)) {
927                 exit_server("reply_sesssetup_and_X: bad smb signature");
928         }
929
930         SSVAL(outbuf,smb_uid,sess_vuid);
931         SSVAL(inbuf,smb_uid,sess_vuid);
932         
933         if (!done_sesssetup)
934                 max_send = MIN(max_send,smb_bufsize);
935         
936         done_sesssetup = True;
937         
938         END_PROFILE(SMBsesssetupX);
939         return chain_reply(inbuf,outbuf,length,bufsize);
940 }