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