r21478: Add 65k length limit for split SPNEGO blobs.
[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 extern struct auth_context *negprot_global_auth_context;
27 extern BOOL global_encrypted_passwords_negotiated;
28 extern BOOL global_spnego_negotiated;
29 extern enum protocol_types Protocol;
30 extern int max_send;
31
32 uint32 global_client_caps = 0;
33
34 /*
35   on a logon error possibly map the error to success if "map to guest"
36   is set approriately
37 */
38 static NTSTATUS do_map_to_guest(NTSTATUS status, auth_serversupplied_info **server_info,
39                                 const char *user, const char *domain)
40 {
41         if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
42                 if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) || 
43                     (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) {
44                         DEBUG(3,("No such user %s [%s] - using guest account\n",
45                                  user, domain));
46                         status = make_server_info_guest(server_info);
47                 }
48         }
49
50         if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
51                 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) {
52                         DEBUG(3,("Registered username %s for guest access\n",user));
53                         status = make_server_info_guest(server_info);
54                 }
55         }
56
57         return status;
58 }
59
60 /****************************************************************************
61  Add the standard 'Samba' signature to the end of the session setup.
62 ****************************************************************************/
63
64 static int add_signature(char *outbuf, char *p)
65 {
66         char *start = p;
67         fstring lanman;
68
69         fstr_sprintf( lanman, "Samba %s", SAMBA_VERSION_STRING);
70
71         p += srvstr_push(outbuf, p, "Unix", -1, STR_TERMINATE);
72         p += srvstr_push(outbuf, p, lanman, -1, STR_TERMINATE);
73         p += srvstr_push(outbuf, p, lp_workgroup(), -1, STR_TERMINATE);
74
75         return PTR_DIFF(p, start);
76 }
77
78 /****************************************************************************
79  Start the signing engine if needed. Don't fail signing here.
80 ****************************************************************************/
81
82 static void sessionsetup_start_signing_engine(const auth_serversupplied_info *server_info, char *inbuf)
83 {
84         if (!server_info->guest && !srv_signing_started()) {
85                 /* We need to start the signing engine
86                  * here but a W2K client sends the old
87                  * "BSRSPYL " signature instead of the
88                  * correct one. Subsequent packets will
89                  * be correct.
90                  */
91                 srv_check_sign_mac(inbuf, False);
92         }
93 }
94
95 /****************************************************************************
96  Send a security blob via a session setup reply.
97 ****************************************************************************/
98
99 static BOOL reply_sesssetup_blob(connection_struct *conn, char *outbuf,
100                                  DATA_BLOB blob, NTSTATUS nt_status)
101 {
102         char *p;
103
104         if (!NT_STATUS_IS_OK(nt_status) && !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
105                 ERROR_NT(nt_status_squash(nt_status));
106         } else {
107                 set_message(outbuf,4,0,True);
108
109                 nt_status = nt_status_squash(nt_status);
110                 SIVAL(outbuf, smb_rcls, NT_STATUS_V(nt_status));
111                 SSVAL(outbuf, smb_vwv0, 0xFF); /* no chaining possible */
112                 SSVAL(outbuf, smb_vwv3, blob.length);
113                 p = smb_buf(outbuf);
114
115                 /* should we cap this? */
116                 memcpy(p, blob.data, blob.length);
117                 p += blob.length;
118
119                 p += add_signature( outbuf, p );
120
121                 set_message_end(outbuf,p);
122         }
123
124         show_msg(outbuf);
125         return send_smb(smbd_server_fd(),outbuf);
126 }
127
128 /****************************************************************************
129  Do a 'guest' logon, getting back the 
130 ****************************************************************************/
131
132 static NTSTATUS check_guest_password(auth_serversupplied_info **server_info) 
133 {
134         struct auth_context *auth_context;
135         auth_usersupplied_info *user_info = NULL;
136         
137         NTSTATUS nt_status;
138         unsigned char chal[8];
139
140         ZERO_STRUCT(chal);
141
142         DEBUG(3,("Got anonymous request\n"));
143
144         if (!NT_STATUS_IS_OK(nt_status = make_auth_context_fixed(&auth_context, chal))) {
145                 return nt_status;
146         }
147
148         if (!make_user_info_guest(&user_info)) {
149                 (auth_context->free)(&auth_context);
150                 return NT_STATUS_NO_MEMORY;
151         }
152         
153         nt_status = auth_context->check_ntlm_password(auth_context, user_info, server_info);
154         (auth_context->free)(&auth_context);
155         free_user_info(&user_info);
156         return nt_status;
157 }
158
159
160 #ifdef HAVE_KRB5
161 /****************************************************************************
162 reply to a session setup spnego negotiate packet for kerberos
163 ****************************************************************************/
164 static int reply_spnego_kerberos(connection_struct *conn, 
165                                  char *inbuf, char *outbuf,
166                                  int length, int bufsize,
167                                  DATA_BLOB *secblob)
168 {
169         TALLOC_CTX *mem_ctx;
170         DATA_BLOB ticket;
171         char *client, *p, *domain;
172         fstring netbios_domain_name;
173         struct passwd *pw;
174         fstring user;
175         int sess_vuid;
176         NTSTATUS ret;
177         PAC_DATA *pac_data;
178         DATA_BLOB ap_rep, ap_rep_wrapped, response;
179         auth_serversupplied_info *server_info = NULL;
180         DATA_BLOB session_key = data_blob(NULL, 0);
181         uint8 tok_id[2];
182         DATA_BLOB nullblob = data_blob(NULL, 0);
183         fstring real_username;
184         BOOL map_domainuser_to_guest = False;
185         BOOL username_was_mapped;
186         PAC_LOGON_INFO *logon_info = NULL;
187
188         ZERO_STRUCT(ticket);
189         ZERO_STRUCT(pac_data);
190         ZERO_STRUCT(ap_rep);
191         ZERO_STRUCT(ap_rep_wrapped);
192         ZERO_STRUCT(response);
193
194         mem_ctx = talloc_init("reply_spnego_kerberos");
195         if (mem_ctx == NULL)
196                 return ERROR_NT(nt_status_squash(NT_STATUS_NO_MEMORY));
197
198         if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) {
199                 talloc_destroy(mem_ctx);
200                 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
201         }
202
203         ret = ads_verify_ticket(mem_ctx, lp_realm(), 0, &ticket, &client, &pac_data, &ap_rep, &session_key);
204
205         data_blob_free(&ticket);
206
207         if (!NT_STATUS_IS_OK(ret)) {
208                 DEBUG(1,("Failed to verify incoming ticket!\n"));       
209                 talloc_destroy(mem_ctx);
210                 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
211         }
212
213         DEBUG(3,("Ticket name is [%s]\n", client));
214
215         p = strchr_m(client, '@');
216         if (!p) {
217                 DEBUG(3,("Doesn't look like a valid principal\n"));
218                 data_blob_free(&ap_rep);
219                 data_blob_free(&session_key);
220                 SAFE_FREE(client);
221                 talloc_destroy(mem_ctx);
222                 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
223         }
224
225         *p = 0;
226
227         /* save the PAC data if we have it */
228
229         if (pac_data) {
230                 logon_info = get_logon_info_from_pac(pac_data);
231                 if (logon_info) {
232                         netsamlogon_cache_store( client, &logon_info->info3 );
233                 }
234         }
235
236         if (!strequal(p+1, lp_realm())) {
237                 DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1));
238                 if (!lp_allow_trusted_domains()) {
239                         data_blob_free(&ap_rep);
240                         data_blob_free(&session_key);
241                         SAFE_FREE(client);
242                         talloc_destroy(mem_ctx);
243                         return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
244                 }
245         }
246
247         /* this gives a fully qualified user name (ie. with full realm).
248            that leads to very long usernames, but what else can we do? */
249
250         domain = p+1;
251
252         if (logon_info && logon_info->info3.hdr_logon_dom.uni_str_len) {
253
254                 unistr2_to_ascii(netbios_domain_name, &logon_info->info3.uni_logon_dom, -1);
255                 domain = netbios_domain_name;
256                 DEBUG(10, ("Mapped to [%s] (using PAC)\n", domain));
257
258         } else {
259
260                 /* If we have winbind running, we can (and must) shorten the
261                    username by using the short netbios name. Otherwise we will
262                    have inconsistent user names. With Kerberos, we get the
263                    fully qualified realm, with ntlmssp we get the short
264                    name. And even w2k3 does use ntlmssp if you for example
265                    connect to an ip address. */
266
267                 struct winbindd_request wb_request;
268                 struct winbindd_response wb_response;
269                 NSS_STATUS wb_result;
270
271                 ZERO_STRUCT(wb_request);
272                 ZERO_STRUCT(wb_response);
273
274                 DEBUG(10, ("Mapping [%s] to short name\n", domain));
275
276                 fstrcpy(wb_request.domain_name, domain);
277
278                 wb_result = winbindd_request_response(WINBINDD_DOMAIN_INFO,
279                                              &wb_request, &wb_response);
280
281                 if (wb_result == NSS_STATUS_SUCCESS) {
282
283                         fstrcpy(netbios_domain_name,
284                                 wb_response.data.domain_info.name);
285                         domain = netbios_domain_name;
286
287                         DEBUG(10, ("Mapped to [%s] (using Winbind)\n", domain));
288                 } else {
289                         DEBUG(3, ("Could not find short name -- winbind "
290                                   "not running?\n"));
291                 }
292         }
293
294         fstr_sprintf(user, "%s%c%s", domain, *lp_winbind_separator(), client);
295         
296         /* lookup the passwd struct, create a new user if necessary */
297
298         username_was_mapped = map_username( user );
299
300         pw = smb_getpwnam( mem_ctx, user, real_username, True );
301
302         if (pw) {
303                 /* if a real user check pam account restrictions */
304                 /* only really perfomed if "obey pam restriction" is true */
305                 /* do this before an eventual mappign to guest occurs */
306                 ret = smb_pam_accountcheck(pw->pw_name);
307                 if (  !NT_STATUS_IS_OK(ret)) {
308                         DEBUG(1, ("PAM account restriction prevents user login\n"));
309                         data_blob_free(&ap_rep);
310                         data_blob_free(&session_key);
311                         TALLOC_FREE(mem_ctx);
312                         return ERROR_NT(nt_status_squash(ret));
313                 }
314         }
315
316         if (!pw) {
317
318                 /* this was originally the behavior of Samba 2.2, if a user
319                    did not have a local uid but has been authenticated, then 
320                    map them to a guest account */
321
322                 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID){ 
323                         map_domainuser_to_guest = True;
324                         fstrcpy(user,lp_guestaccount());
325                         pw = smb_getpwnam( mem_ctx, user, real_username, True );
326                 } 
327
328                 /* extra sanity check that the guest account is valid */
329
330                 if ( !pw ) {
331                         DEBUG(1,("Username %s is invalid on this system\n", user));
332                         SAFE_FREE(client);
333                         data_blob_free(&ap_rep);
334                         data_blob_free(&session_key);
335                         TALLOC_FREE(mem_ctx);
336                         return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
337                 }
338         }
339
340         /* setup the string used by %U */
341         
342         sub_set_smb_name( real_username );
343         reload_services(True);
344
345         if ( map_domainuser_to_guest ) {
346                 make_server_info_guest(&server_info);
347         } else if (logon_info) {
348                 /* pass the unmapped username here since map_username() 
349                    will be called again from inside make_server_info_info3() */
350                 
351                 ret = make_server_info_info3(mem_ctx, client, domain, 
352                                              &server_info, &logon_info->info3);
353                 if ( !NT_STATUS_IS_OK(ret) ) {
354                         DEBUG(1,("make_server_info_info3 failed: %s!\n",
355                                  nt_errstr(ret)));
356                         SAFE_FREE(client);
357                         data_blob_free(&ap_rep);
358                         data_blob_free(&session_key);
359                         TALLOC_FREE(mem_ctx);
360                         return ERROR_NT(nt_status_squash(ret));
361                 }
362
363         } else {
364                 ret = make_server_info_pw(&server_info, real_username, pw);
365
366                 if ( !NT_STATUS_IS_OK(ret) ) {
367                         DEBUG(1,("make_server_info_pw failed: %s!\n",
368                                  nt_errstr(ret)));
369                         SAFE_FREE(client);
370                         data_blob_free(&ap_rep);
371                         data_blob_free(&session_key);
372                         TALLOC_FREE(mem_ctx);
373                         return ERROR_NT(nt_status_squash(ret));
374                 }
375
376                 /* make_server_info_pw does not set the domain. Without this
377                  * we end up with the local netbios name in substitutions for
378                  * %D. */
379
380                 if (server_info->sam_account != NULL) {
381                         pdb_set_domain(server_info->sam_account, domain, PDB_SET);
382                 }
383         }
384
385         server_info->was_mapped |= username_was_mapped;
386         
387         /* we need to build the token for the user. make_server_info_guest()
388            already does this */
389         
390         if ( !server_info->ptok ) {
391                 ret = create_local_token( server_info );
392                 if ( !NT_STATUS_IS_OK(ret) ) {
393                         SAFE_FREE(client);
394                         data_blob_free(&ap_rep);
395                         data_blob_free(&session_key);
396                         TALLOC_FREE( mem_ctx );
397                         TALLOC_FREE( server_info );
398                         return ERROR_NT(nt_status_squash(ret));
399                 }
400         }
401
402         /* register_vuid keeps the server info */
403         /* register_vuid takes ownership of session_key, no need to free after this.
404            A better interface would copy it.... */
405         sess_vuid = register_vuid(server_info, session_key, nullblob, client);
406
407         SAFE_FREE(client);
408
409         if (sess_vuid == UID_FIELD_INVALID ) {
410                 ret = NT_STATUS_LOGON_FAILURE;
411         } else {
412                 /* current_user_info is changed on new vuid */
413                 reload_services( True );
414
415                 set_message(outbuf,4,0,True);
416                 SSVAL(outbuf, smb_vwv3, 0);
417                         
418                 if (server_info->guest) {
419                         SSVAL(outbuf,smb_vwv2,1);
420                 }
421                 
422                 SSVAL(outbuf, smb_uid, sess_vuid);
423
424                 sessionsetup_start_signing_engine(server_info, inbuf);
425         }
426
427         /* wrap that up in a nice GSS-API wrapping */
428         if (NT_STATUS_IS_OK(ret)) {
429                 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep, TOK_ID_KRB_AP_REP);
430         } else {
431                 ap_rep_wrapped = data_blob(NULL, 0);
432         }
433         response = spnego_gen_auth_response(&ap_rep_wrapped, ret, OID_KERBEROS5_OLD);
434         reply_sesssetup_blob(conn, outbuf, response, ret);
435
436         data_blob_free(&ap_rep);
437         data_blob_free(&ap_rep_wrapped);
438         data_blob_free(&response);
439         TALLOC_FREE(mem_ctx);
440
441         return -1; /* already replied */
442 }
443 #endif
444
445 /****************************************************************************
446  Send a session setup reply, wrapped in SPNEGO.
447  Get vuid and check first.
448  End the NTLMSSP exchange context if we are OK/complete fail
449  This should be split into two functions, one to handle each
450  leg of the NTLM auth steps.
451 ***************************************************************************/
452
453 static BOOL reply_spnego_ntlmssp(connection_struct *conn, char *inbuf, char *outbuf,
454                                  uint16 vuid,
455                                  AUTH_NTLMSSP_STATE **auth_ntlmssp_state,
456                                  DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status, 
457                                  BOOL wrap) 
458 {
459         BOOL ret;
460         DATA_BLOB response;
461         struct auth_serversupplied_info *server_info = NULL;
462
463         if (NT_STATUS_IS_OK(nt_status)) {
464                 server_info = (*auth_ntlmssp_state)->server_info;
465         } else {
466                 nt_status = do_map_to_guest(nt_status, 
467                                             &server_info, 
468                                             (*auth_ntlmssp_state)->ntlmssp_state->user, 
469                                             (*auth_ntlmssp_state)->ntlmssp_state->domain);
470         }
471
472         if (NT_STATUS_IS_OK(nt_status)) {
473                 int sess_vuid;
474                 DATA_BLOB nullblob = data_blob(NULL, 0);
475                 DATA_BLOB session_key = data_blob((*auth_ntlmssp_state)->ntlmssp_state->session_key.data, (*auth_ntlmssp_state)->ntlmssp_state->session_key.length);
476
477                 /* register_vuid keeps the server info */
478                 sess_vuid = register_vuid(server_info, session_key, nullblob, (*auth_ntlmssp_state)->ntlmssp_state->user);
479                 (*auth_ntlmssp_state)->server_info = NULL;
480
481                 if (sess_vuid == UID_FIELD_INVALID ) {
482                         nt_status = NT_STATUS_LOGON_FAILURE;
483                 } else {
484                         
485                         /* current_user_info is changed on new vuid */
486                         reload_services( True );
487
488                         set_message(outbuf,4,0,True);
489                         SSVAL(outbuf, smb_vwv3, 0);
490                         
491                         if (server_info->guest) {
492                                 SSVAL(outbuf,smb_vwv2,1);
493                         }
494                         
495                         SSVAL(outbuf,smb_uid,sess_vuid);
496
497                         sessionsetup_start_signing_engine(server_info, inbuf);
498                 }
499         }
500
501         if (wrap) {
502                 response = spnego_gen_auth_response(ntlmssp_blob, nt_status, OID_NTLMSSP);
503         } else {
504                 response = *ntlmssp_blob;
505         }
506
507         ret = reply_sesssetup_blob(conn, outbuf, response, nt_status);
508         if (wrap) {
509                 data_blob_free(&response);
510         }
511
512         /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
513            and the other end, that we are not finished yet. */
514
515         if (!ret || !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
516                 /* NB. This is *NOT* an error case. JRA */
517                 auth_ntlmssp_end(auth_ntlmssp_state);
518                 /* Kill the intermediate vuid */
519                 invalidate_vuid(vuid);
520         }
521
522         return ret;
523 }
524
525 /****************************************************************************
526  Reply to a session setup spnego negotiate packet.
527 ****************************************************************************/
528
529 static int reply_spnego_negotiate(connection_struct *conn, 
530                                   char *inbuf,
531                                   char *outbuf,
532                                   uint16 vuid,
533                                   int length, int bufsize,
534                                   DATA_BLOB blob1,
535                                   AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
536 {
537         char *OIDs[ASN1_MAX_OIDS];
538         DATA_BLOB secblob;
539         int i;
540         DATA_BLOB chal;
541 #ifdef HAVE_KRB5
542         BOOL got_kerberos_mechanism = False;
543 #endif
544         NTSTATUS nt_status;
545
546         /* parse out the OIDs and the first sec blob */
547         if (!parse_negTokenTarg(blob1, OIDs, &secblob)) {
548                 /* Kill the intermediate vuid */
549                 invalidate_vuid(vuid);
550
551                 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
552         }
553
554         /* only look at the first OID for determining the mechToken --
555            accoirding to RFC2478, we should choose the one we want 
556            and renegotiate, but i smell a client bug here..  
557            
558            Problem observed when connecting to a member (samba box) 
559            of an AD domain as a user in a Samba domain.  Samba member 
560            server sent back krb5/mskrb5/ntlmssp as mechtypes, but the 
561            client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an 
562            NTLMSSP mechtoken.                 --jerry              */
563
564 #ifdef HAVE_KRB5        
565         if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||
566             strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
567                 got_kerberos_mechanism = True;
568         }
569 #endif
570                 
571         for (i=0;OIDs[i];i++) {
572                 DEBUG(3,("Got OID %s\n", OIDs[i]));
573                 free(OIDs[i]);
574         }
575         DEBUG(3,("Got secblob of size %lu\n", (unsigned long)secblob.length));
576
577 #ifdef HAVE_KRB5
578         if ( got_kerberos_mechanism && ((lp_security()==SEC_ADS) || lp_use_kerberos_keytab()) ) {
579                 int ret = reply_spnego_kerberos(conn, inbuf, outbuf, 
580                                                 length, bufsize, &secblob);
581                 data_blob_free(&secblob);
582                 /* Kill the intermediate vuid */
583                 invalidate_vuid(vuid);
584
585                 return ret;
586         }
587 #endif
588
589         if (*auth_ntlmssp_state) {
590                 auth_ntlmssp_end(auth_ntlmssp_state);
591         }
592
593         nt_status = auth_ntlmssp_start(auth_ntlmssp_state);
594         if (!NT_STATUS_IS_OK(nt_status)) {
595                 /* Kill the intermediate vuid */
596                 invalidate_vuid(vuid);
597
598                 return ERROR_NT(nt_status_squash(nt_status));
599         }
600
601         nt_status = auth_ntlmssp_update(*auth_ntlmssp_state, 
602                                         secblob, &chal);
603
604         data_blob_free(&secblob);
605
606         reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid, auth_ntlmssp_state,
607                              &chal, nt_status, True);
608
609         data_blob_free(&chal);
610
611         /* already replied */
612         return -1;
613 }
614         
615 /****************************************************************************
616  Reply to a session setup spnego auth packet.
617 ****************************************************************************/
618
619 static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
620                              uint16 vuid,
621                              int length, int bufsize,
622                              DATA_BLOB blob1,
623                              AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
624 {
625         DATA_BLOB auth, auth_reply;
626         NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
627
628         if (!spnego_parse_auth(blob1, &auth)) {
629 #if 0
630                 file_save("auth.dat", blob1.data, blob1.length);
631 #endif
632                 /* Kill the intermediate vuid */
633                 invalidate_vuid(vuid);
634
635                 return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
636         }
637         
638         if (!*auth_ntlmssp_state) {
639                 /* Kill the intermediate vuid */
640                 invalidate_vuid(vuid);
641
642                 /* auth before negotiatiate? */
643                 return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
644         }
645         
646         nt_status = auth_ntlmssp_update(*auth_ntlmssp_state, 
647                                         auth, &auth_reply);
648
649         data_blob_free(&auth);
650
651         reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid, 
652                              auth_ntlmssp_state,
653                              &auth_reply, nt_status, True);
654                 
655         data_blob_free(&auth_reply);
656
657         /* and tell smbd that we have already replied to this packet */
658         return -1;
659 }
660
661 /****************************************************************************
662  List to store partial SPNEGO auth fragments.
663 ****************************************************************************/
664
665 static struct pending_auth_data *pd_list;
666
667 /****************************************************************************
668  Delete an entry on the list.
669 ****************************************************************************/
670
671 static void delete_partial_auth(struct pending_auth_data *pad)
672 {
673         DLIST_REMOVE(pd_list, pad);
674         data_blob_free(&pad->partial_data);
675         SAFE_FREE(pad);
676 }
677
678 /****************************************************************************
679  Search for a partial SPNEGO auth fragment matching an smbpid.
680 ****************************************************************************/
681
682 static struct pending_auth_data *get_pending_auth_data(uint16 smbpid)
683 {
684         struct pending_auth_data *pad;
685
686         for (pad = pd_list; pad; pad = pad->next) {
687                 if (pad->smbpid == smbpid) {
688                         break;
689                 }
690         }
691         return pad;
692 }
693
694 /****************************************************************************
695  Check the size of an SPNEGO blob. If we need more return NT_STATUS_MORE_PROCESSING_REQUIRED,
696  else return NT_STATUS_OK. Don't allow the blob to be more than 64k.
697 ****************************************************************************/
698
699 static NTSTATUS check_spnego_blob_complete(uint16 smbpid, uint16 vuid, DATA_BLOB *pblob)
700 {
701         struct pending_auth_data *pad;
702         ASN1_DATA data;
703         size_t needed_len = 0;
704
705         /* Ensure we have some data. */
706         if (pblob->length == 0) {
707                 /* Caller can cope. */
708                 DEBUG(2,("check_spnego_blob_complete: zero blob length !\n"));
709                 delete_partial_auth(pad);
710                 return NT_STATUS_OK;
711         }
712
713         pad = get_pending_auth_data(smbpid);
714
715         /* Were we waiting for more data ? */
716         if (pad) {
717                 DATA_BLOB tmp_blob;
718                 size_t copy_len = MIN(65536, pblob->length);
719
720                 /* Integer wrap paranoia.... */
721
722                 if (pad->partial_data.length + copy_len < pad->partial_data.length ||
723                     pad->partial_data.length + copy_len < copy_len) {
724
725                         DEBUG(2,("check_spnego_blob_complete: integer wrap "
726                                 "pad->partial_data.length = %u, "
727                                 "copy_len = %u\n",
728                                 (unsigned int)pad->partial_data.length,
729                                 (unsigned int)copy_len ));
730
731                         delete_partial_auth(pad);
732                         return NT_STATUS_INVALID_PARAMETER;
733                 }
734
735                 DEBUG(10,("check_spnego_blob_complete: "
736                         "pad->partial_data.length = %u, "
737                         "pad->needed_len = %u, "
738                         "copy_len = %u, "
739                         "pblob->length = %u,\n",
740                         (unsigned int)pad->partial_data.length,
741                         (unsigned int)pad->needed_len,
742                         (unsigned int)copy_len,
743                         (unsigned int)pblob->length ));
744
745                 tmp_blob = data_blob(NULL,
746                                 pad->partial_data.length + copy_len);
747
748                 /* Concatenate the two (up to copy_len) bytes. */
749                 memcpy(tmp_blob.data,
750                         pad->partial_data.data,
751                         pad->partial_data.length);
752                 memcpy(tmp_blob.data + pad->partial_data.length,
753                         pblob->data,
754                         copy_len);
755
756                 /* Replace the partial data. */
757                 data_blob_free(&pad->partial_data);
758                 pad->partial_data = tmp_blob;
759                 ZERO_STRUCT(tmp_blob);
760
761                 /* Are we done ? */
762                 if (pblob->length >= pad->needed_len) {
763                         /* Yes, replace pblob. */
764                         data_blob_free(pblob);
765                         *pblob = pad->partial_data;
766                         ZERO_STRUCT(pad->partial_data);
767                         delete_partial_auth(pad);
768                         return NT_STATUS_OK;
769                 }
770
771                 /* Still need more data. */
772                 pad->needed_len -= copy_len;
773                 return NT_STATUS_MORE_PROCESSING_REQUIRED;
774         }
775
776         if ((pblob->data[0] != ASN1_APPLICATION(0)) &&
777             (pblob->data[0] != ASN1_CONTEXT(1))) {
778                 /* Not something we can determine the
779                  * length of.
780                  */
781                 return NT_STATUS_OK;
782         }
783
784         /* This is a new SPNEGO sessionsetup - see if
785          * the data given in this blob is enough.
786          */
787
788         asn1_load(&data, *pblob);
789         asn1_start_tag(&data, pblob->data[0]);
790         if (data.has_error || data.nesting == NULL) {
791                 asn1_free(&data);
792                 /* Let caller catch. */
793                 return NT_STATUS_OK;
794         }
795
796         /* Integer wrap paranoia.... */
797
798         if (data.nesting->taglen + data.nesting->start < data.nesting->taglen ||
799             data.nesting->taglen + data.nesting->start < data.nesting->start) {
800
801                 DEBUG(2,("check_spnego_blob_complete: integer wrap "
802                         "data.nesting->taglen = %u, "
803                         "data.nesting->start = %u\n",
804                         (unsigned int)data.nesting->taglen,
805                         (unsigned int)data.nesting->start ));
806
807                 asn1_free(&data);
808                 return NT_STATUS_INVALID_PARAMETER;
809         }
810
811         /* Total length of the needed asn1 is the tag length
812          * plus the current offset. */
813
814         needed_len = data.nesting->taglen + data.nesting->start;
815         asn1_free(&data);
816
817         DEBUG(10,("check_spnego_blob_complete: needed_len = %u, "
818                 "pblob->length = %u\n",
819                 (unsigned int)needed_len,
820                 (unsigned int)pblob->length ));
821
822         if (needed_len <= pblob->length) {
823                 /* Nothing to do - blob is complete. */
824                 return NT_STATUS_OK;
825         }
826
827         /* Refuse the blob if it's bigger than 64k. */
828         if (needed_len > 65536) {
829                 DEBUG(2,("check_spnego_blob_complete: needed_len too large (%u)\n",
830                         (unsigned int)needed_len ));
831                 return NT_STATUS_INVALID_PARAMETER;
832         }
833
834         /* We must store this blob until complete. */
835         pad = SMB_MALLOC(sizeof(struct pending_auth_data));
836         if (!pad) {
837                 return NT_STATUS_NO_MEMORY;
838         }
839         pad->needed_len = needed_len - pblob->length;
840         pad->partial_data = data_blob(pblob->data, pblob->length);
841         if (pad->partial_data.data == NULL) {
842                 SAFE_FREE(pad);
843                 return NT_STATUS_NO_MEMORY;
844         }
845         pad->smbpid = smbpid;
846         pad->vuid = vuid;
847         DLIST_ADD(pd_list, pad);
848
849         return NT_STATUS_MORE_PROCESSING_REQUIRED;
850 }
851
852 /****************************************************************************
853  Reply to a session setup command.
854  conn POINTER CAN BE NULL HERE !
855 ****************************************************************************/
856
857 static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,
858                                         char *outbuf,
859                                         int length,int bufsize)
860 {
861         uint8 *p;
862         DATA_BLOB blob1;
863         int ret;
864         size_t bufrem;
865         fstring native_os, native_lanman, primary_domain;
866         char *p2;
867         uint16 data_blob_len = SVAL(inbuf, smb_vwv7);
868         enum remote_arch_types ra_type = get_remote_arch();
869         int vuid = SVAL(inbuf,smb_uid);
870         user_struct *vuser = NULL;
871         NTSTATUS status = NT_STATUS_OK;
872         uint16 smbpid = SVAL(inbuf,smb_pid);
873
874         DEBUG(3,("Doing spnego session setup\n"));
875
876         if (global_client_caps == 0) {
877                 global_client_caps = IVAL(inbuf,smb_vwv10);
878
879                 if (!(global_client_caps & CAP_STATUS32)) {
880                         remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
881                 }
882
883         }
884                 
885         p = (uint8 *)smb_buf(inbuf);
886
887         if (data_blob_len == 0) {
888                 /* an invalid request */
889                 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
890         }
891
892         bufrem = smb_bufrem(inbuf, p);
893         /* pull the spnego blob */
894         blob1 = data_blob(p, MIN(bufrem, data_blob_len));
895
896 #if 0
897         file_save("negotiate.dat", blob1.data, blob1.length);
898 #endif
899
900         p2 = inbuf + smb_vwv13 + data_blob_len;
901         p2 += srvstr_pull_buf(inbuf, native_os, p2, sizeof(native_os), STR_TERMINATE);
902         p2 += srvstr_pull_buf(inbuf, native_lanman, p2, sizeof(native_lanman), STR_TERMINATE);
903         p2 += srvstr_pull_buf(inbuf, primary_domain, p2, sizeof(primary_domain), STR_TERMINATE);
904         DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n", 
905                 native_os, native_lanman, primary_domain));
906
907         if ( ra_type == RA_WIN2K ) {
908                 /* Windows 2003 doesn't set the native lanman string, 
909                    but does set primary domain which is a bug I think */
910                            
911                 if ( !strlen(native_lanman) ) {
912                         ra_lanman_string( primary_domain );
913                 } else {
914                         ra_lanman_string( native_lanman );
915                 }
916         }
917                 
918         vuser = get_partial_auth_user_struct(vuid);
919         if (!vuser) {
920                 struct pending_auth_data *pad = get_pending_auth_data(smbpid);
921                 if (pad) {
922                         DEBUG(10,("reply_sesssetup_and_X_spnego: found pending vuid %u\n",
923                                 (unsigned int)pad->vuid ));
924                         vuid = pad->vuid;
925                         vuser = get_partial_auth_user_struct(vuid);
926                 }
927         }
928
929         if (!vuser) {
930                 vuid = register_vuid(NULL, data_blob(NULL, 0), data_blob(NULL, 0), NULL);
931                 if (vuid == UID_FIELD_INVALID ) {
932                         data_blob_free(&blob1);
933                         return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
934                 }
935         
936                 vuser = get_partial_auth_user_struct(vuid);
937         }
938
939         if (!vuser) {
940                 data_blob_free(&blob1);
941                 return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
942         }
943         
944         SSVAL(outbuf,smb_uid,vuid);
945
946         /* Large (greater than 4k) SPNEGO blobs are split into multiple
947          * sessionsetup requests as the Windows limit on the security blob
948          * field is 4k. Bug #4400. JRA.
949          */
950
951         status = check_spnego_blob_complete(smbpid, vuid, &blob1);
952         if (!NT_STATUS_IS_OK(status)) {
953                 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
954                         /* Real error - kill the intermediate vuid */
955                         invalidate_vuid(vuid);
956                 }
957                 data_blob_free(&blob1);
958                 return ERROR_NT(nt_status_squash(status));
959         }
960
961         if (blob1.data[0] == ASN1_APPLICATION(0)) {
962                 /* its a negTokenTarg packet */
963                 ret = reply_spnego_negotiate(conn, inbuf, outbuf, vuid, length, bufsize, blob1,
964                                              &vuser->auth_ntlmssp_state);
965                 data_blob_free(&blob1);
966                 return ret;
967         }
968
969         if (blob1.data[0] == ASN1_CONTEXT(1)) {
970                 /* its a auth packet */
971                 ret = reply_spnego_auth(conn, inbuf, outbuf, vuid, length, bufsize, blob1,
972                                         &vuser->auth_ntlmssp_state);
973                 data_blob_free(&blob1);
974                 return ret;
975         }
976
977         if (strncmp((char *)(blob1.data), "NTLMSSP", 7) == 0) {
978                 DATA_BLOB chal;
979                 if (!vuser->auth_ntlmssp_state) {
980                         status = auth_ntlmssp_start(&vuser->auth_ntlmssp_state);
981                         if (!NT_STATUS_IS_OK(status)) {
982                                 /* Kill the intermediate vuid */
983                                 invalidate_vuid(vuid);
984                                 data_blob_free(&blob1);
985                                 return ERROR_NT(nt_status_squash(status));
986                         }
987                 }
988
989                 status = auth_ntlmssp_update(vuser->auth_ntlmssp_state,
990                                                 blob1, &chal);
991                 
992                 data_blob_free(&blob1);
993                 
994                 reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid, 
995                                            &vuser->auth_ntlmssp_state,
996                                            &chal, status, False);
997                 data_blob_free(&chal);
998                 return -1;
999         }
1000
1001         /* what sort of packet is this? */
1002         DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
1003
1004         data_blob_free(&blob1);
1005
1006         return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
1007 }
1008
1009 /****************************************************************************
1010  On new VC == 0, shutdown *all* old connections and users.
1011  It seems that only NT4.x does this. At W2K and above (XP etc.).
1012  a new session setup with VC==0 is ignored.
1013 ****************************************************************************/
1014
1015 static int shutdown_other_smbds(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf,
1016                                 void *p)
1017 {
1018         struct sessionid *sessionid = (struct sessionid *)dbuf.dptr;
1019         const char *ip = (const char *)p;
1020
1021         if (!process_exists(pid_to_procid(sessionid->pid))) {
1022                 return 0;
1023         }
1024
1025         if (sessionid->pid == sys_getpid()) {
1026                 return 0;
1027         }
1028
1029         if (strcmp(ip, sessionid->ip_addr) != 0) {
1030                 return 0;
1031         }
1032
1033         message_send_pid(pid_to_procid(sessionid->pid), MSG_SHUTDOWN,
1034                          NULL, 0, True);
1035         return 0;
1036 }
1037
1038 static void setup_new_vc_session(void)
1039 {
1040         DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x compatible we would close all old resources.\n"));
1041 #if 0
1042         conn_close_all();
1043         invalidate_all_vuids();
1044 #endif
1045         if (lp_reset_on_zero_vc()) {
1046                 session_traverse(shutdown_other_smbds, client_addr());
1047         }
1048 }
1049
1050 /****************************************************************************
1051  Reply to a session setup command.
1052 ****************************************************************************/
1053
1054 int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
1055                           int length,int bufsize)
1056 {
1057         int sess_vuid;
1058         int   smb_bufsize;    
1059         DATA_BLOB lm_resp;
1060         DATA_BLOB nt_resp;
1061         DATA_BLOB plaintext_password;
1062         fstring user;
1063         fstring sub_user; /* Sainitised username for substituion */
1064         fstring domain;
1065         fstring native_os;
1066         fstring native_lanman;
1067         fstring primary_domain;
1068         static BOOL done_sesssetup = False;
1069         auth_usersupplied_info *user_info = NULL;
1070         auth_serversupplied_info *server_info = NULL;
1071
1072         NTSTATUS nt_status;
1073
1074         BOOL doencrypt = global_encrypted_passwords_negotiated;
1075
1076         DATA_BLOB session_key;
1077         
1078         START_PROFILE(SMBsesssetupX);
1079
1080         ZERO_STRUCT(lm_resp);
1081         ZERO_STRUCT(nt_resp);
1082         ZERO_STRUCT(plaintext_password);
1083
1084         DEBUG(3,("wct=%d flg2=0x%x\n", CVAL(inbuf, smb_wct), SVAL(inbuf, smb_flg2)));
1085
1086         /* a SPNEGO session setup has 12 command words, whereas a normal
1087            NT1 session setup has 13. See the cifs spec. */
1088         if (CVAL(inbuf, smb_wct) == 12 &&
1089             (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
1090                 if (!global_spnego_negotiated) {
1091                         DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt at SPNEGO session setup when it was not negoitiated.\n"));
1092                         return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
1093                 }
1094
1095                 if (SVAL(inbuf,smb_vwv4) == 0) {
1096                         setup_new_vc_session();
1097                 }
1098                 return reply_sesssetup_and_X_spnego(conn, inbuf, outbuf, length, bufsize);
1099         }
1100
1101         smb_bufsize = SVAL(inbuf,smb_vwv2);
1102
1103         if (Protocol < PROTOCOL_NT1) {
1104                 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
1105
1106                 /* Never do NT status codes with protocols before NT1 as we don't get client caps. */
1107                 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1108
1109                 if ((passlen1 > MAX_PASS_LEN) || (passlen1 > smb_bufrem(inbuf, smb_buf(inbuf)))) {
1110                         return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
1111                 }
1112
1113                 if (doencrypt) {
1114                         lm_resp = data_blob(smb_buf(inbuf), passlen1);
1115                 } else {
1116                         plaintext_password = data_blob(smb_buf(inbuf), passlen1+1);
1117                         /* Ensure null termination */
1118                         plaintext_password.data[passlen1] = 0;
1119                 }
1120
1121                 srvstr_pull_buf(inbuf, user, smb_buf(inbuf)+passlen1, sizeof(user), STR_TERMINATE);
1122                 *domain = 0;
1123
1124         } else {
1125                 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
1126                 uint16 passlen2 = SVAL(inbuf,smb_vwv8);
1127                 enum remote_arch_types ra_type = get_remote_arch();
1128                 char *p = smb_buf(inbuf);    
1129                 char *save_p = smb_buf(inbuf);
1130                 uint16 byte_count;
1131                         
1132
1133                 if(global_client_caps == 0) {
1134                         global_client_caps = IVAL(inbuf,smb_vwv11);
1135                 
1136                         if (!(global_client_caps & CAP_STATUS32)) {
1137                                 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1138                         }
1139
1140                         /* client_caps is used as final determination if client is NT or Win95. 
1141                            This is needed to return the correct error codes in some
1142                            circumstances.
1143                         */
1144                 
1145                         if(ra_type == RA_WINNT || ra_type == RA_WIN2K || ra_type == RA_WIN95) {
1146                                 if(!(global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))) {
1147                                         set_remote_arch( RA_WIN95);
1148                                 }
1149                         }
1150                 }
1151
1152                 if (!doencrypt) {
1153                         /* both Win95 and WinNT stuff up the password lengths for
1154                            non-encrypting systems. Uggh. 
1155                            
1156                            if passlen1==24 its a win95 system, and its setting the
1157                            password length incorrectly. Luckily it still works with the
1158                            default code because Win95 will null terminate the password
1159                            anyway 
1160                            
1161                            if passlen1>0 and passlen2>0 then maybe its a NT box and its
1162                            setting passlen2 to some random value which really stuffs
1163                            things up. we need to fix that one.  */
1164                         
1165                         if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 && passlen2 != 1)
1166                                 passlen2 = 0;
1167                 }
1168                 
1169                 /* check for nasty tricks */
1170                 if (passlen1 > MAX_PASS_LEN || passlen1 > smb_bufrem(inbuf, p)) {
1171                         return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
1172                 }
1173
1174                 if (passlen2 > MAX_PASS_LEN || passlen2 > smb_bufrem(inbuf, p+passlen1)) {
1175                         return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
1176                 }
1177
1178                 /* Save the lanman2 password and the NT md4 password. */
1179                 
1180                 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
1181                         doencrypt = False;
1182                 }
1183
1184                 if (doencrypt) {
1185                         lm_resp = data_blob(p, passlen1);
1186                         nt_resp = data_blob(p+passlen1, passlen2);
1187                 } else {
1188                         pstring pass;
1189                         BOOL unic=SVAL(inbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS;
1190
1191 #if 0
1192                         /* This was the previous fix. Not sure if it's still valid. JRA. */
1193                         if ((ra_type == RA_WINNT) && (passlen2 == 0) && unic && passlen1) {
1194                                 /* NT4.0 stuffs up plaintext unicode password lengths... */
1195                                 srvstr_pull(inbuf, pass, smb_buf(inbuf) + 1,
1196                                         sizeof(pass), passlen1, STR_TERMINATE);
1197 #endif
1198
1199                         if (unic && (passlen2 == 0) && passlen1) {
1200                                 /* Only a ascii plaintext password was sent. */
1201                                 srvstr_pull(inbuf, pass, smb_buf(inbuf), sizeof(pass),
1202                                         passlen1, STR_TERMINATE|STR_ASCII);
1203                         } else {
1204                                 srvstr_pull(inbuf, pass, smb_buf(inbuf), 
1205                                         sizeof(pass),  unic ? passlen2 : passlen1, 
1206                                         STR_TERMINATE);
1207                         }
1208                         plaintext_password = data_blob(pass, strlen(pass)+1);
1209                 }
1210                 
1211                 p += passlen1 + passlen2;
1212                 p += srvstr_pull_buf(inbuf, user, p, sizeof(user), STR_TERMINATE);
1213                 p += srvstr_pull_buf(inbuf, domain, p, sizeof(domain), STR_TERMINATE);
1214                 p += srvstr_pull_buf(inbuf, native_os, p, sizeof(native_os), STR_TERMINATE);
1215                 p += srvstr_pull_buf(inbuf, native_lanman, p, sizeof(native_lanman), STR_TERMINATE);
1216
1217                 /* not documented or decoded by Ethereal but there is one more string 
1218                    in the extra bytes which is the same as the PrimaryDomain when using 
1219                    extended security.  Windows NT 4 and 2003 use this string to store 
1220                    the native lanman string. Windows 9x does not include a string here 
1221                    at all so we have to check if we have any extra bytes left */
1222                 
1223                 byte_count = SVAL(inbuf, smb_vwv13);
1224                 if ( PTR_DIFF(p, save_p) < byte_count)
1225                         p += srvstr_pull_buf(inbuf, primary_domain, p, sizeof(primary_domain), STR_TERMINATE);
1226                 else 
1227                         fstrcpy( primary_domain, "null" );
1228
1229                 DEBUG(3,("Domain=[%s]  NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
1230                          domain, native_os, native_lanman, primary_domain));
1231
1232                 if ( ra_type == RA_WIN2K ) {
1233                         if ( strlen(native_lanman) == 0 )
1234                                 ra_lanman_string( primary_domain );
1235                         else
1236                                 ra_lanman_string( native_lanman );
1237                 }
1238
1239         }
1240
1241         if (SVAL(inbuf,smb_vwv4) == 0) {
1242                 setup_new_vc_session();
1243         }
1244
1245         DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n", domain, user, get_remote_machine_name()));
1246
1247         if (*user) {
1248                 if (global_spnego_negotiated) {
1249                         
1250                         /* This has to be here, because this is a perfectly valid behaviour for guest logons :-( */
1251                         
1252                         DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt at 'normal' session setup after negotiating spnego.\n"));
1253                         return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
1254                 }
1255                 fstrcpy(sub_user, user);
1256         } else {
1257                 fstrcpy(sub_user, lp_guestaccount());
1258         }
1259
1260         sub_set_smb_name(sub_user);
1261
1262         reload_services(True);
1263         
1264         if (lp_security() == SEC_SHARE) {
1265                 /* in share level we should ignore any passwords */
1266
1267                 data_blob_free(&lm_resp);
1268                 data_blob_free(&nt_resp);
1269                 data_blob_clear_free(&plaintext_password);
1270
1271                 map_username(sub_user);
1272                 add_session_user(sub_user);
1273                 add_session_workgroup(domain);
1274                 /* Then force it to null for the benfit of the code below */
1275                 *user = 0;
1276         }
1277         
1278         if (!*user) {
1279
1280                 nt_status = check_guest_password(&server_info);
1281
1282         } else if (doencrypt) {
1283                 if (!negprot_global_auth_context) {
1284                         DEBUG(0, ("reply_sesssetup_and_X:  Attempted encrypted session setup without negprot denied!\n"));
1285                         return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
1286                 }
1287                 nt_status = make_user_info_for_reply_enc(&user_info, user, domain,
1288                                                          lm_resp, nt_resp);
1289                 if (NT_STATUS_IS_OK(nt_status)) {
1290                         nt_status = negprot_global_auth_context->check_ntlm_password(negprot_global_auth_context, 
1291                                                                                      user_info, 
1292                                                                                      &server_info);
1293                 }
1294         } else {
1295                 struct auth_context *plaintext_auth_context = NULL;
1296                 const uint8 *chal;
1297
1298                 nt_status = make_auth_context_subsystem(&plaintext_auth_context);
1299
1300                 if (NT_STATUS_IS_OK(nt_status)) {
1301                         chal = plaintext_auth_context->get_ntlm_challenge(plaintext_auth_context);
1302                         
1303                         if (!make_user_info_for_reply(&user_info, 
1304                                                       user, domain, chal,
1305                                                       plaintext_password)) {
1306                                 nt_status = NT_STATUS_NO_MEMORY;
1307                         }
1308                 
1309                         if (NT_STATUS_IS_OK(nt_status)) {
1310                                 nt_status = plaintext_auth_context->check_ntlm_password(plaintext_auth_context, 
1311                                                                                         user_info, 
1312                                                                                         &server_info); 
1313                                 
1314                                 (plaintext_auth_context->free)(&plaintext_auth_context);
1315                         }
1316                 }
1317         }
1318
1319         free_user_info(&user_info);
1320         
1321         if (!NT_STATUS_IS_OK(nt_status)) {
1322                 nt_status = do_map_to_guest(nt_status, &server_info, user, domain);
1323         }
1324         
1325         if (!NT_STATUS_IS_OK(nt_status)) {
1326                 data_blob_free(&nt_resp);
1327                 data_blob_free(&lm_resp);
1328                 data_blob_clear_free(&plaintext_password);
1329                 return ERROR_NT(nt_status_squash(nt_status));
1330         }
1331
1332         /* Ensure we can't possible take a code path leading to a null defref. */
1333         if (!server_info) {
1334                 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
1335         }
1336
1337         nt_status = create_local_token(server_info);
1338         if (!NT_STATUS_IS_OK(nt_status)) {
1339                 DEBUG(10, ("create_local_token failed: %s\n",
1340                            nt_errstr(nt_status)));
1341                 data_blob_free(&nt_resp);
1342                 data_blob_free(&lm_resp);
1343                 data_blob_clear_free(&plaintext_password);
1344                 return ERROR_NT(nt_status_squash(nt_status));
1345         }
1346
1347         if (server_info->user_session_key.data) {
1348                 session_key = data_blob(server_info->user_session_key.data, server_info->user_session_key.length);
1349         } else {
1350                 session_key = data_blob(NULL, 0);
1351         }
1352
1353         data_blob_clear_free(&plaintext_password);
1354         
1355         /* it's ok - setup a reply */
1356         set_message(outbuf,3,0,True);
1357         if (Protocol >= PROTOCOL_NT1) {
1358                 char *p = smb_buf( outbuf );
1359                 p += add_signature( outbuf, p );
1360                 set_message_end( outbuf, p );
1361                 /* perhaps grab OS version here?? */
1362         }
1363         
1364         if (server_info->guest) {
1365                 SSVAL(outbuf,smb_vwv2,1);
1366         }
1367
1368         /* register the name and uid as being validated, so further connections
1369            to a uid can get through without a password, on the same VC */
1370
1371         if (lp_security() == SEC_SHARE) {
1372                 sess_vuid = UID_FIELD_INVALID;
1373                 data_blob_free(&session_key);
1374                 TALLOC_FREE(server_info);
1375         } else {
1376                 /* register_vuid keeps the server info */
1377                 sess_vuid = register_vuid(server_info, session_key,
1378                                           nt_resp.data ? nt_resp : lm_resp,
1379                                           sub_user);
1380                 if (sess_vuid == UID_FIELD_INVALID) {
1381                         data_blob_free(&nt_resp);
1382                         data_blob_free(&lm_resp);
1383                         return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
1384                 }
1385
1386                 /* current_user_info is changed on new vuid */
1387                 reload_services( True );
1388
1389                 sessionsetup_start_signing_engine(server_info, inbuf);
1390         }
1391
1392         data_blob_free(&nt_resp);
1393         data_blob_free(&lm_resp);
1394         
1395         SSVAL(outbuf,smb_uid,sess_vuid);
1396         SSVAL(inbuf,smb_uid,sess_vuid);
1397         
1398         if (!done_sesssetup)
1399                 max_send = MIN(max_send,smb_bufsize);
1400         
1401         done_sesssetup = True;
1402         
1403         END_PROFILE(SMBsesssetupX);
1404         return chain_reply(inbuf,outbuf,length,bufsize);
1405 }