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