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