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