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