Merge commit 'samba/v3-2-test' into v3-2-stable
[bbaumbach/samba-autobuild/.git] / source / smbd / sesssetup.c
1 /*
2    Unix SMB/CIFS implementation.
3    handle SMBsessionsetup
4    Copyright (C) Andrew Tridgell 1998-2001
5    Copyright (C) Andrew Bartlett      2001
6    Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002
7    Copyright (C) Luke Howard          2003
8    Copyright (C) Volker Lendecke      2007
9    Copyright (C) Jeremy Allison       2007
10
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 3 of the License, or
14    (at your option) any later version.
15
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20
21    You should have received a copy of the GNU General Public License
22    along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 */
24
25 #include "includes.h"
26
27 extern struct auth_context *negprot_global_auth_context;
28 extern bool global_encrypted_passwords_negotiated;
29 extern bool global_spnego_negotiated;
30 extern enum protocol_types Protocol;
31 extern int max_send;
32
33 uint32 global_client_caps = 0;
34
35 /*
36   on a logon error possibly map the error to success if "map to guest"
37   is set approriately
38 */
39 static NTSTATUS do_map_to_guest(NTSTATUS status,
40                                 auth_serversupplied_info **server_info,
41                                 const char *user, const char *domain)
42 {
43         if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
44                 if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) ||
45                     (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) {
46                         DEBUG(3,("No such user %s [%s] - using guest account\n",
47                                  user, domain));
48                         status = make_server_info_guest(server_info);
49                 }
50         }
51
52         if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
53                 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) {
54                         DEBUG(3,("Registered username %s for guest access\n",
55                                 user));
56                         status = make_server_info_guest(server_info);
57                 }
58         }
59
60         return status;
61 }
62
63 /****************************************************************************
64  Add the standard 'Samba' signature to the end of the session setup.
65 ****************************************************************************/
66
67 static int push_signature(uint8 **outbuf)
68 {
69         char *lanman;
70         int result, tmp;
71
72         result = 0;
73
74         tmp = message_push_string(outbuf, "Unix", STR_TERMINATE);
75
76         if (tmp == -1) return -1;
77         result += tmp;
78
79         if (asprintf(&lanman, "Samba %s", SAMBA_VERSION_STRING) != -1) {
80                 tmp = message_push_string(outbuf, lanman, STR_TERMINATE);
81                 SAFE_FREE(lanman);
82         }
83         else {
84                 tmp = message_push_string(outbuf, "Samba", STR_TERMINATE);
85         }
86
87         if (tmp == -1) return -1;
88         result += tmp;
89
90         tmp = message_push_string(outbuf, lp_workgroup(), STR_TERMINATE);
91
92         if (tmp == -1) return -1;
93         result += tmp;
94
95         return result;
96 }
97
98 /****************************************************************************
99  Start the signing engine if needed. Don't fail signing here.
100 ****************************************************************************/
101
102 static void sessionsetup_start_signing_engine(
103                         const auth_serversupplied_info *server_info,
104                         const uint8 *inbuf)
105 {
106         if (!server_info->guest && !srv_signing_started()) {
107                 /* We need to start the signing engine
108                  * here but a W2K client sends the old
109                  * "BSRSPYL " signature instead of the
110                  * correct one. Subsequent packets will
111                  * be correct.
112                  */
113                 srv_check_sign_mac((char *)inbuf, False);
114         }
115 }
116
117 /****************************************************************************
118  Send a security blob via a session setup reply.
119 ****************************************************************************/
120
121 static void reply_sesssetup_blob(struct smb_request *req,
122                                  DATA_BLOB blob,
123                                  NTSTATUS nt_status)
124 {
125         if (!NT_STATUS_IS_OK(nt_status) &&
126             !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
127                 reply_nterror(req, nt_status_squash(nt_status));
128         } else {
129                 nt_status = nt_status_squash(nt_status);
130                 SIVAL(req->outbuf, smb_rcls, NT_STATUS_V(nt_status));
131                 SSVAL(req->outbuf, smb_vwv0, 0xFF); /* no chaining possible */
132                 SSVAL(req->outbuf, smb_vwv3, blob.length);
133
134                 if ((message_push_blob(&req->outbuf, blob) == -1)
135                     || (push_signature(&req->outbuf) == -1)) {
136                         reply_nterror(req, NT_STATUS_NO_MEMORY);
137                 }
138         }
139
140         show_msg((char *)req->outbuf);
141         srv_send_smb(smbd_server_fd(),(char *)req->outbuf,req->encrypted);
142         TALLOC_FREE(req->outbuf);
143 }
144
145 /****************************************************************************
146  Do a 'guest' logon, getting back the
147 ****************************************************************************/
148
149 static NTSTATUS check_guest_password(auth_serversupplied_info **server_info)
150 {
151         struct auth_context *auth_context;
152         auth_usersupplied_info *user_info = NULL;
153
154         NTSTATUS nt_status;
155         unsigned char chal[8];
156
157         ZERO_STRUCT(chal);
158
159         DEBUG(3,("Got anonymous request\n"));
160
161         if (!NT_STATUS_IS_OK(nt_status = make_auth_context_fixed(&auth_context,
162                                         chal))) {
163                 return nt_status;
164         }
165
166         if (!make_user_info_guest(&user_info)) {
167                 (auth_context->free)(&auth_context);
168                 return NT_STATUS_NO_MEMORY;
169         }
170
171         nt_status = auth_context->check_ntlm_password(auth_context,
172                                                 user_info,
173                                                 server_info);
174         (auth_context->free)(&auth_context);
175         free_user_info(&user_info);
176         return nt_status;
177 }
178
179
180 #ifdef HAVE_KRB5
181
182 #if 0
183 /* Experiment that failed. See "only happens with a KDC" comment below. */
184 /****************************************************************************
185  Cerate a clock skew error blob for a Windows client.
186 ****************************************************************************/
187
188 static bool make_krb5_skew_error(DATA_BLOB *pblob_out)
189 {
190         krb5_context context = NULL;
191         krb5_error_code kerr = 0;
192         krb5_data reply;
193         krb5_principal host_princ = NULL;
194         char *host_princ_s = NULL;
195         bool ret = False;
196
197         *pblob_out = data_blob_null;
198
199         initialize_krb5_error_table();
200         kerr = krb5_init_context(&context);
201         if (kerr) {
202                 return False;
203         }
204         /* Create server principal. */
205         asprintf(&host_princ_s, "%s$@%s", global_myname(), lp_realm());
206         if (!host_princ_s) {
207                 goto out;
208         }
209         strlower_m(host_princ_s);
210
211         kerr = smb_krb5_parse_name(context, host_princ_s, &host_princ);
212         if (kerr) {
213                 DEBUG(10,("make_krb5_skew_error: smb_krb5_parse_name failed "
214                         "for name %s: Error %s\n",
215                         host_princ_s, error_message(kerr) ));
216                 goto out;
217         }
218
219         kerr = smb_krb5_mk_error(context, KRB5KRB_AP_ERR_SKEW,
220                         host_princ, &reply);
221         if (kerr) {
222                 DEBUG(10,("make_krb5_skew_error: smb_krb5_mk_error "
223                         "failed: Error %s\n",
224                         error_message(kerr) ));
225                 goto out;
226         }
227
228         *pblob_out = data_blob(reply.data, reply.length);
229         kerberos_free_data_contents(context,&reply);
230         ret = True;
231
232   out:
233
234         if (host_princ_s) {
235                 SAFE_FREE(host_princ_s);
236         }
237         if (host_princ) {
238                 krb5_free_principal(context, host_princ);
239         }
240         krb5_free_context(context);
241         return ret;
242 }
243 #endif
244
245 /****************************************************************************
246  Reply to a session setup spnego negotiate packet for kerberos.
247 ****************************************************************************/
248
249 static void reply_spnego_kerberos(struct smb_request *req,
250                                   DATA_BLOB *secblob,
251                                   uint16 vuid,
252                                   bool *p_invalidate_vuid)
253 {
254         TALLOC_CTX *mem_ctx;
255         DATA_BLOB ticket;
256         char *client, *p, *domain;
257         fstring netbios_domain_name;
258         struct passwd *pw;
259         fstring user;
260         int sess_vuid = req->vuid;
261         NTSTATUS ret = NT_STATUS_OK;
262         PAC_DATA *pac_data = NULL;
263         DATA_BLOB ap_rep, ap_rep_wrapped, response;
264         auth_serversupplied_info *server_info = NULL;
265         DATA_BLOB session_key = data_blob_null;
266         uint8 tok_id[2];
267         DATA_BLOB nullblob = data_blob_null;
268         fstring real_username;
269         bool map_domainuser_to_guest = False;
270         bool username_was_mapped;
271         PAC_LOGON_INFO *logon_info = NULL;
272
273         ZERO_STRUCT(ticket);
274         ZERO_STRUCT(ap_rep);
275         ZERO_STRUCT(ap_rep_wrapped);
276         ZERO_STRUCT(response);
277
278         /* Normally we will always invalidate the intermediate vuid. */
279         *p_invalidate_vuid = True;
280
281         mem_ctx = talloc_init("reply_spnego_kerberos");
282         if (mem_ctx == NULL) {
283                 reply_nterror(req, nt_status_squash(NT_STATUS_NO_MEMORY));
284                 return;
285         }
286
287         if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) {
288                 talloc_destroy(mem_ctx);
289                 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
290                 return;
291         }
292
293         ret = ads_verify_ticket(mem_ctx, lp_realm(), 0, &ticket,
294                                 &client, &pac_data, &ap_rep,
295                                 &session_key, True);
296
297         data_blob_free(&ticket);
298
299         if (!NT_STATUS_IS_OK(ret)) {
300 #if 0
301                 /* Experiment that failed.
302                  * See "only happens with a KDC" comment below. */
303
304                 if (NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
305
306                         /*
307                          * Windows in this case returns
308                          * NT_STATUS_MORE_PROCESSING_REQUIRED
309                          * with a negTokenTarg blob containing an krb5_error
310                          * struct ASN1 encoded containing KRB5KRB_AP_ERR_SKEW.
311                          * The client then fixes its clock and continues rather
312                          * than giving an error. JRA.
313                          * -- Looks like this only happens with a KDC. JRA.
314                          */
315
316                         bool ok = make_krb5_skew_error(&ap_rep);
317                         if (!ok) {
318                                 talloc_destroy(mem_ctx);
319                                 return ERROR_NT(nt_status_squash(
320                                                 NT_STATUS_LOGON_FAILURE));
321                         }
322                         ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep,
323                                         TOK_ID_KRB_ERROR);
324                         response = spnego_gen_auth_response(&ap_rep_wrapped,
325                                         ret, OID_KERBEROS5_OLD);
326                         reply_sesssetup_blob(conn, inbuf, outbuf, response,
327                                         NT_STATUS_MORE_PROCESSING_REQUIRED);
328
329                         /*
330                          * In this one case we don't invalidate the
331                          * intermediate vuid as we're expecting the client
332                          * to re-use it for the next sessionsetupX packet. JRA.
333                          */
334
335                         *p_invalidate_vuid = False;
336
337                         data_blob_free(&ap_rep);
338                         data_blob_free(&ap_rep_wrapped);
339                         data_blob_free(&response);
340                         talloc_destroy(mem_ctx);
341                         return -1; /* already replied */
342                 }
343 #else
344                 if (!NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
345                         ret = NT_STATUS_LOGON_FAILURE;
346                 }
347 #endif
348                 DEBUG(1,("Failed to verify incoming ticket with error %s!\n",
349                                 nt_errstr(ret)));
350                 talloc_destroy(mem_ctx);
351                 reply_nterror(req, nt_status_squash(ret));
352                 return;
353         }
354
355         DEBUG(3,("Ticket name is [%s]\n", client));
356
357         p = strchr_m(client, '@');
358         if (!p) {
359                 DEBUG(3,("Doesn't look like a valid principal\n"));
360                 data_blob_free(&ap_rep);
361                 data_blob_free(&session_key);
362                 SAFE_FREE(client);
363                 talloc_destroy(mem_ctx);
364                 reply_nterror(req,nt_status_squash(NT_STATUS_LOGON_FAILURE));
365                 return;
366         }
367
368         *p = 0;
369
370         /* save the PAC data if we have it */
371
372         if (pac_data) {
373                 logon_info = get_logon_info_from_pac(pac_data);
374                 if (logon_info) {
375                         netsamlogon_cache_store( client, &logon_info->info3 );
376                 }
377         }
378
379         if (!strequal(p+1, lp_realm())) {
380                 DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1));
381                 if (!lp_allow_trusted_domains()) {
382                         data_blob_free(&ap_rep);
383                         data_blob_free(&session_key);
384                         SAFE_FREE(client);
385                         talloc_destroy(mem_ctx);
386                         reply_nterror(req, nt_status_squash(
387                                               NT_STATUS_LOGON_FAILURE));
388                         return;
389                 }
390         }
391
392         /* this gives a fully qualified user name (ie. with full realm).
393            that leads to very long usernames, but what else can we do? */
394
395         domain = p+1;
396
397         if (logon_info && logon_info->info3.hdr_logon_dom.uni_str_len) {
398                 unistr2_to_ascii(netbios_domain_name,
399                                 &logon_info->info3.uni_logon_dom,
400                                 sizeof(netbios_domain_name));
401                 domain = netbios_domain_name;
402                 DEBUG(10, ("Mapped to [%s] (using PAC)\n", domain));
403
404         } else {
405
406                 /* If we have winbind running, we can (and must) shorten the
407                    username by using the short netbios name. Otherwise we will
408                    have inconsistent user names. With Kerberos, we get the
409                    fully qualified realm, with ntlmssp we get the short
410                    name. And even w2k3 does use ntlmssp if you for example
411                    connect to an ip address. */
412
413                 struct winbindd_request wb_request;
414                 struct winbindd_response wb_response;
415                 NSS_STATUS wb_result;
416
417                 ZERO_STRUCT(wb_request);
418                 ZERO_STRUCT(wb_response);
419
420                 DEBUG(10, ("Mapping [%s] to short name\n", domain));
421
422                 fstrcpy(wb_request.domain_name, domain);
423
424                 wb_result = winbindd_request_response(WINBINDD_DOMAIN_INFO,
425                                              &wb_request, &wb_response);
426
427                 if (wb_result == NSS_STATUS_SUCCESS) {
428
429                         fstrcpy(netbios_domain_name,
430                                 wb_response.data.domain_info.name);
431                         domain = netbios_domain_name;
432
433                         DEBUG(10, ("Mapped to [%s] (using Winbind)\n", domain));
434                 } else {
435                         DEBUG(3, ("Could not find short name -- winbind "
436                                   "not running?\n"));
437                 }
438         }
439
440         fstr_sprintf(user, "%s%c%s", domain, *lp_winbind_separator(), client);
441
442         /* lookup the passwd struct, create a new user if necessary */
443
444         username_was_mapped = map_username( user );
445
446         pw = smb_getpwnam( mem_ctx, user, real_username, True );
447
448         if (pw) {
449                 /* if a real user check pam account restrictions */
450                 /* only really perfomed if "obey pam restriction" is true */
451                 /* do this before an eventual mappign to guest occurs */
452                 ret = smb_pam_accountcheck(pw->pw_name);
453                 if (  !NT_STATUS_IS_OK(ret)) {
454                         DEBUG(1,("PAM account restriction "
455                                 "prevents user login\n"));
456                         data_blob_free(&ap_rep);
457                         data_blob_free(&session_key);
458                         TALLOC_FREE(mem_ctx);
459                         reply_nterror(req, nt_status_squash(ret));
460                         return;
461                 }
462         }
463
464         if (!pw) {
465
466                 /* this was originally the behavior of Samba 2.2, if a user
467                    did not have a local uid but has been authenticated, then
468                    map them to a guest account */
469
470                 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID){
471                         map_domainuser_to_guest = True;
472                         fstrcpy(user,lp_guestaccount());
473                         pw = smb_getpwnam( mem_ctx, user, real_username, True );
474                 }
475
476                 /* extra sanity check that the guest account is valid */
477
478                 if ( !pw ) {
479                         DEBUG(1,("Username %s is invalid on this system\n",
480                                 user));
481                         SAFE_FREE(client);
482                         data_blob_free(&ap_rep);
483                         data_blob_free(&session_key);
484                         TALLOC_FREE(mem_ctx);
485                         reply_nterror(req, nt_status_squash(
486                                               NT_STATUS_LOGON_FAILURE));
487                         return;
488                 }
489         }
490
491         /* setup the string used by %U */
492
493         sub_set_smb_name( real_username );
494         reload_services(True);
495
496         if ( map_domainuser_to_guest ) {
497                 make_server_info_guest(&server_info);
498         } else if (logon_info) {
499                 /* pass the unmapped username here since map_username()
500                    will be called again from inside make_server_info_info3() */
501
502                 ret = make_server_info_info3(mem_ctx, client, domain,
503                                              &server_info, &logon_info->info3);
504                 if ( !NT_STATUS_IS_OK(ret) ) {
505                         DEBUG(1,("make_server_info_info3 failed: %s!\n",
506                                  nt_errstr(ret)));
507                         SAFE_FREE(client);
508                         data_blob_free(&ap_rep);
509                         data_blob_free(&session_key);
510                         TALLOC_FREE(mem_ctx);
511                         reply_nterror(req, nt_status_squash(ret));
512                         return;
513                 }
514
515         } else {
516                 ret = make_server_info_pw(&server_info, real_username, pw);
517
518                 if ( !NT_STATUS_IS_OK(ret) ) {
519                         DEBUG(1,("make_server_info_pw failed: %s!\n",
520                                  nt_errstr(ret)));
521                         SAFE_FREE(client);
522                         data_blob_free(&ap_rep);
523                         data_blob_free(&session_key);
524                         TALLOC_FREE(mem_ctx);
525                         reply_nterror(req, nt_status_squash(ret));
526                         return;
527                 }
528
529                 /* make_server_info_pw does not set the domain. Without this
530                  * we end up with the local netbios name in substitutions for
531                  * %D. */
532
533                 if (server_info->sam_account != NULL) {
534                         pdb_set_domain(server_info->sam_account,
535                                         domain, PDB_SET);
536                 }
537         }
538
539         if (username_was_mapped) {
540                 server_info->was_mapped = username_was_mapped;
541         }
542
543         /* we need to build the token for the user. make_server_info_guest()
544            already does this */
545
546         if ( !server_info->ptok ) {
547                 ret = create_local_token( server_info );
548                 if ( !NT_STATUS_IS_OK(ret) ) {
549                         SAFE_FREE(client);
550                         data_blob_free(&ap_rep);
551                         data_blob_free(&session_key);
552                         TALLOC_FREE( mem_ctx );
553                         TALLOC_FREE( server_info );
554                         reply_nterror(req, nt_status_squash(ret));
555                         return;
556                 }
557         }
558
559         /* register_existing_vuid keeps the server info */
560         /* register_existing_vuid takes ownership of session_key on success,
561          * no need to free after this on success. A better interface would copy
562          * it.... */
563
564         if (!is_partial_auth_vuid(sess_vuid)) {
565                 sess_vuid = register_initial_vuid();
566         }
567         sess_vuid = register_existing_vuid(sess_vuid,
568                                         server_info,
569                                         session_key,
570                                         nullblob,
571                                         client);
572
573         SAFE_FREE(client);
574
575         reply_outbuf(req, 4, 0);
576         SSVAL(req->outbuf,smb_uid,sess_vuid);
577
578         if (sess_vuid == UID_FIELD_INVALID ) {
579                 ret = NT_STATUS_LOGON_FAILURE;
580                 data_blob_free(&session_key);
581         } else {
582                 /* current_user_info is changed on new vuid */
583                 reload_services( True );
584
585                 SSVAL(req->outbuf, smb_vwv3, 0);
586
587                 if (server_info->guest) {
588                         SSVAL(req->outbuf,smb_vwv2,1);
589                 }
590
591                 SSVAL(req->outbuf, smb_uid, sess_vuid);
592
593                 sessionsetup_start_signing_engine(server_info, req->inbuf);
594                 /* Successful logon. Keep this vuid. */
595                 *p_invalidate_vuid = False;
596         }
597
598         /* wrap that up in a nice GSS-API wrapping */
599         if (NT_STATUS_IS_OK(ret)) {
600                 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep,
601                                 TOK_ID_KRB_AP_REP);
602         } else {
603                 ap_rep_wrapped = data_blob_null;
604         }
605         response = spnego_gen_auth_response(&ap_rep_wrapped, ret,
606                         OID_KERBEROS5_OLD);
607         reply_sesssetup_blob(req, response, ret);
608
609         data_blob_free(&ap_rep);
610         data_blob_free(&ap_rep_wrapped);
611         data_blob_free(&response);
612         TALLOC_FREE(mem_ctx);
613 }
614
615 #endif
616
617 /****************************************************************************
618  Send a session setup reply, wrapped in SPNEGO.
619  Get vuid and check first.
620  End the NTLMSSP exchange context if we are OK/complete fail
621  This should be split into two functions, one to handle each
622  leg of the NTLM auth steps.
623 ***************************************************************************/
624
625 static void reply_spnego_ntlmssp(struct smb_request *req,
626                                  uint16 vuid,
627                                  AUTH_NTLMSSP_STATE **auth_ntlmssp_state,
628                                  DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status,
629                                  bool wrap)
630 {
631         DATA_BLOB response;
632         struct auth_serversupplied_info *server_info = NULL;
633
634         if (NT_STATUS_IS_OK(nt_status)) {
635                 server_info = (*auth_ntlmssp_state)->server_info;
636         } else {
637                 nt_status = do_map_to_guest(nt_status,
638                             &server_info,
639                             (*auth_ntlmssp_state)->ntlmssp_state->user,
640                             (*auth_ntlmssp_state)->ntlmssp_state->domain);
641         }
642
643         reply_outbuf(req, 4, 0);
644
645         SSVAL(req->outbuf, smb_uid, vuid);
646
647         if (NT_STATUS_IS_OK(nt_status)) {
648                 DATA_BLOB nullblob = data_blob_null;
649                 DATA_BLOB session_key =
650                         data_blob(
651                         (*auth_ntlmssp_state)->ntlmssp_state->session_key.data,
652                         (*auth_ntlmssp_state)->ntlmssp_state->session_key.length);
653
654                 if (!is_partial_auth_vuid(vuid)) {
655                         data_blob_free(&session_key);
656                         nt_status = NT_STATUS_LOGON_FAILURE;
657                         goto out;
658                 }
659                 /* register_existing_vuid keeps the server info */
660                 if (register_existing_vuid(vuid,
661                                 server_info,
662                                 session_key, nullblob,
663                                 (*auth_ntlmssp_state)->ntlmssp_state->user) !=
664                                         vuid) {
665                         data_blob_free(&session_key);
666                         nt_status = NT_STATUS_LOGON_FAILURE;
667                         goto out;
668                 }
669
670                 (*auth_ntlmssp_state)->server_info = NULL;
671
672                 /* current_user_info is changed on new vuid */
673                 reload_services( True );
674
675                 SSVAL(req->outbuf, smb_vwv3, 0);
676
677                 if (server_info->guest) {
678                         SSVAL(req->outbuf,smb_vwv2,1);
679                 }
680
681                 sessionsetup_start_signing_engine(server_info,
682                                                   (uint8 *)req->inbuf);
683         }
684
685   out:
686
687         if (wrap) {
688                 response = spnego_gen_auth_response(ntlmssp_blob,
689                                 nt_status, OID_NTLMSSP);
690         } else {
691                 response = *ntlmssp_blob;
692         }
693
694         reply_sesssetup_blob(req, response, nt_status);
695         if (wrap) {
696                 data_blob_free(&response);
697         }
698
699         /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
700            and the other end, that we are not finished yet. */
701
702         if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
703                 /* NB. This is *NOT* an error case. JRA */
704                 auth_ntlmssp_end(auth_ntlmssp_state);
705                 if (!NT_STATUS_IS_OK(nt_status)) {
706                         /* Kill the intermediate vuid */
707                         invalidate_vuid(vuid);
708                 }
709         }
710 }
711
712 /****************************************************************************
713  Is this a krb5 mechanism ?
714 ****************************************************************************/
715
716 NTSTATUS parse_spnego_mechanisms(DATA_BLOB blob_in, DATA_BLOB *pblob_out,
717                 bool *p_is_krb5)
718 {
719         char *OIDs[ASN1_MAX_OIDS];
720         int i;
721
722         *p_is_krb5 = False;
723
724         /* parse out the OIDs and the first sec blob */
725         if (!parse_negTokenTarg(blob_in, OIDs, pblob_out)) {
726                 return NT_STATUS_LOGON_FAILURE;
727         }
728
729         /* only look at the first OID for determining the mechToken --
730            according to RFC2478, we should choose the one we want
731            and renegotiate, but i smell a client bug here..
732
733            Problem observed when connecting to a member (samba box)
734            of an AD domain as a user in a Samba domain.  Samba member
735            server sent back krb5/mskrb5/ntlmssp as mechtypes, but the
736            client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an
737            NTLMSSP mechtoken.                 --jerry              */
738
739 #ifdef HAVE_KRB5
740         if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||
741             strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
742                 *p_is_krb5 = True;
743         }
744 #endif
745
746         for (i=0;OIDs[i];i++) {
747                 DEBUG(5,("parse_spnego_mechanisms: Got OID %s\n", OIDs[i]));
748                 free(OIDs[i]);
749         }
750         return NT_STATUS_OK;
751 }
752
753 /****************************************************************************
754  Reply to a session setup spnego negotiate packet.
755 ****************************************************************************/
756
757 static void reply_spnego_negotiate(struct smb_request *req,
758                                    uint16 vuid,
759                                    DATA_BLOB blob1,
760                                    AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
761 {
762         DATA_BLOB secblob;
763         DATA_BLOB chal;
764         bool got_kerberos_mechanism = False;
765         NTSTATUS status;
766
767         status = parse_spnego_mechanisms(blob1, &secblob,
768                         &got_kerberos_mechanism);
769         if (!NT_STATUS_IS_OK(status)) {
770                 /* Kill the intermediate vuid */
771                 invalidate_vuid(vuid);
772                 reply_nterror(req, nt_status_squash(status));
773                 return;
774         }
775
776         DEBUG(3,("reply_spnego_negotiate: Got secblob of size %lu\n",
777                                 (unsigned long)secblob.length));
778
779 #ifdef HAVE_KRB5
780         if ( got_kerberos_mechanism && ((lp_security()==SEC_ADS) ||
781                                 lp_use_kerberos_keytab()) ) {
782                 bool destroy_vuid = True;
783                 reply_spnego_kerberos(req, &secblob, vuid,
784                                       &destroy_vuid);
785                 data_blob_free(&secblob);
786                 if (destroy_vuid) {
787                         /* Kill the intermediate vuid */
788                         invalidate_vuid(vuid);
789                 }
790                 return;
791         }
792 #endif
793
794         if (*auth_ntlmssp_state) {
795                 auth_ntlmssp_end(auth_ntlmssp_state);
796         }
797
798         status = auth_ntlmssp_start(auth_ntlmssp_state);
799         if (!NT_STATUS_IS_OK(status)) {
800                 /* Kill the intermediate vuid */
801                 invalidate_vuid(vuid);
802                 reply_nterror(req, nt_status_squash(status));
803                 return;
804         }
805
806         status = auth_ntlmssp_update(*auth_ntlmssp_state,
807                                         secblob, &chal);
808
809         data_blob_free(&secblob);
810
811         reply_spnego_ntlmssp(req, vuid, auth_ntlmssp_state,
812                              &chal, status, True);
813
814         data_blob_free(&chal);
815
816         /* already replied */
817         return;
818 }
819
820 /****************************************************************************
821  Reply to a session setup spnego auth packet.
822 ****************************************************************************/
823
824 static void reply_spnego_auth(struct smb_request *req,
825                               uint16 vuid,
826                               DATA_BLOB blob1,
827                               AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
828 {
829         DATA_BLOB auth = data_blob_null;
830         DATA_BLOB auth_reply = data_blob_null;
831         DATA_BLOB secblob = data_blob_null;
832         NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
833
834         if (!spnego_parse_auth(blob1, &auth)) {
835 #if 0
836                 file_save("auth.dat", blob1.data, blob1.length);
837 #endif
838                 /* Kill the intermediate vuid */
839                 invalidate_vuid(vuid);
840
841                 reply_nterror(req, nt_status_squash(
842                                       NT_STATUS_INVALID_PARAMETER));
843                 return;
844         }
845
846         if (auth.data[0] == ASN1_APPLICATION(0)) {
847                 /* Might be a second negTokenTarg packet */
848
849                 bool got_krb5_mechanism = False;
850                 status = parse_spnego_mechanisms(auth, &secblob,
851                                 &got_krb5_mechanism);
852                 if (NT_STATUS_IS_OK(status)) {
853                         DEBUG(3,("reply_spnego_auth: Got secblob of size %lu\n",
854                                         (unsigned long)secblob.length));
855 #ifdef HAVE_KRB5
856                         if ( got_krb5_mechanism && ((lp_security()==SEC_ADS) ||
857                                                 lp_use_kerberos_keytab()) ) {
858                                 bool destroy_vuid = True;
859                                 reply_spnego_kerberos(req, &secblob,
860                                                       vuid, &destroy_vuid);
861                                 data_blob_free(&secblob);
862                                 data_blob_free(&auth);
863                                 if (destroy_vuid) {
864                                         /* Kill the intermediate vuid */
865                                         invalidate_vuid(vuid);
866                                 }
867                                 return;
868                         }
869 #endif
870                 }
871         }
872
873         /* If we get here it wasn't a negTokenTarg auth packet. */
874         data_blob_free(&secblob);
875
876         if (!*auth_ntlmssp_state) {
877                 /* Kill the intermediate vuid */
878                 invalidate_vuid(vuid);
879
880                 /* auth before negotiatiate? */
881                 reply_nterror(req, nt_status_squash(
882                                       NT_STATUS_INVALID_PARAMETER));
883                 return;
884         }
885
886         status = auth_ntlmssp_update(*auth_ntlmssp_state,
887                                         auth, &auth_reply);
888
889         data_blob_free(&auth);
890
891         reply_spnego_ntlmssp(req, vuid,
892                              auth_ntlmssp_state,
893                              &auth_reply, status, True);
894
895         data_blob_free(&auth_reply);
896
897         /* and tell smbd that we have already replied to this packet */
898         return;
899 }
900
901 /****************************************************************************
902  List to store partial SPNEGO auth fragments.
903 ****************************************************************************/
904
905 static struct pending_auth_data *pd_list;
906
907 /****************************************************************************
908  Delete an entry on the list.
909 ****************************************************************************/
910
911 static void delete_partial_auth(struct pending_auth_data *pad)
912 {
913         if (!pad) {
914                 return;
915         }
916         DLIST_REMOVE(pd_list, pad);
917         data_blob_free(&pad->partial_data);
918         SAFE_FREE(pad);
919 }
920
921 /****************************************************************************
922  Search for a partial SPNEGO auth fragment matching an smbpid.
923 ****************************************************************************/
924
925 static struct pending_auth_data *get_pending_auth_data(uint16 smbpid)
926 {
927         struct pending_auth_data *pad;
928
929         for (pad = pd_list; pad; pad = pad->next) {
930                 if (pad->smbpid == smbpid) {
931                         break;
932                 }
933         }
934         return pad;
935 }
936
937 /****************************************************************************
938  Check the size of an SPNEGO blob. If we need more return
939  NT_STATUS_MORE_PROCESSING_REQUIRED, else return NT_STATUS_OK. Don't allow
940  the blob to be more than 64k.
941 ****************************************************************************/
942
943 static NTSTATUS check_spnego_blob_complete(uint16 smbpid, uint16 vuid,
944                 DATA_BLOB *pblob)
945 {
946         struct pending_auth_data *pad = NULL;
947         ASN1_DATA data;
948         size_t needed_len = 0;
949
950         pad = get_pending_auth_data(smbpid);
951
952         /* Ensure we have some data. */
953         if (pblob->length == 0) {
954                 /* Caller can cope. */
955                 DEBUG(2,("check_spnego_blob_complete: zero blob length !\n"));
956                 delete_partial_auth(pad);
957                 return NT_STATUS_OK;
958         }
959
960         /* Were we waiting for more data ? */
961         if (pad) {
962                 DATA_BLOB tmp_blob;
963                 size_t copy_len = MIN(65536, pblob->length);
964
965                 /* Integer wrap paranoia.... */
966
967                 if (pad->partial_data.length + copy_len <
968                                 pad->partial_data.length ||
969                     pad->partial_data.length + copy_len < copy_len) {
970
971                         DEBUG(2,("check_spnego_blob_complete: integer wrap "
972                                 "pad->partial_data.length = %u, "
973                                 "copy_len = %u\n",
974                                 (unsigned int)pad->partial_data.length,
975                                 (unsigned int)copy_len ));
976
977                         delete_partial_auth(pad);
978                         return NT_STATUS_INVALID_PARAMETER;
979                 }
980
981                 DEBUG(10,("check_spnego_blob_complete: "
982                         "pad->partial_data.length = %u, "
983                         "pad->needed_len = %u, "
984                         "copy_len = %u, "
985                         "pblob->length = %u,\n",
986                         (unsigned int)pad->partial_data.length,
987                         (unsigned int)pad->needed_len,
988                         (unsigned int)copy_len,
989                         (unsigned int)pblob->length ));
990
991                 tmp_blob = data_blob(NULL,
992                                 pad->partial_data.length + copy_len);
993
994                 /* Concatenate the two (up to copy_len) bytes. */
995                 memcpy(tmp_blob.data,
996                         pad->partial_data.data,
997                         pad->partial_data.length);
998                 memcpy(tmp_blob.data + pad->partial_data.length,
999                         pblob->data,
1000                         copy_len);
1001
1002                 /* Replace the partial data. */
1003                 data_blob_free(&pad->partial_data);
1004                 pad->partial_data = tmp_blob;
1005                 ZERO_STRUCT(tmp_blob);
1006
1007                 /* Are we done ? */
1008                 if (pblob->length >= pad->needed_len) {
1009                         /* Yes, replace pblob. */
1010                         data_blob_free(pblob);
1011                         *pblob = pad->partial_data;
1012                         ZERO_STRUCT(pad->partial_data);
1013                         delete_partial_auth(pad);
1014                         return NT_STATUS_OK;
1015                 }
1016
1017                 /* Still need more data. */
1018                 pad->needed_len -= copy_len;
1019                 return NT_STATUS_MORE_PROCESSING_REQUIRED;
1020         }
1021
1022         if ((pblob->data[0] != ASN1_APPLICATION(0)) &&
1023             (pblob->data[0] != ASN1_CONTEXT(1))) {
1024                 /* Not something we can determine the
1025                  * length of.
1026                  */
1027                 return NT_STATUS_OK;
1028         }
1029
1030         /* This is a new SPNEGO sessionsetup - see if
1031          * the data given in this blob is enough.
1032          */
1033
1034         asn1_load(&data, *pblob);
1035         asn1_start_tag(&data, pblob->data[0]);
1036         if (data.has_error || data.nesting == NULL) {
1037                 asn1_free(&data);
1038                 /* Let caller catch. */
1039                 return NT_STATUS_OK;
1040         }
1041
1042         /* Integer wrap paranoia.... */
1043
1044         if (data.nesting->taglen + data.nesting->start < data.nesting->taglen ||
1045             data.nesting->taglen + data.nesting->start < data.nesting->start) {
1046
1047                 DEBUG(2,("check_spnego_blob_complete: integer wrap "
1048                         "data.nesting->taglen = %u, "
1049                         "data.nesting->start = %u\n",
1050                         (unsigned int)data.nesting->taglen,
1051                         (unsigned int)data.nesting->start ));
1052
1053                 asn1_free(&data);
1054                 return NT_STATUS_INVALID_PARAMETER;
1055         }
1056
1057         /* Total length of the needed asn1 is the tag length
1058          * plus the current offset. */
1059
1060         needed_len = data.nesting->taglen + data.nesting->start;
1061         asn1_free(&data);
1062
1063         DEBUG(10,("check_spnego_blob_complete: needed_len = %u, "
1064                 "pblob->length = %u\n",
1065                 (unsigned int)needed_len,
1066                 (unsigned int)pblob->length ));
1067
1068         if (needed_len <= pblob->length) {
1069                 /* Nothing to do - blob is complete. */
1070                 return NT_STATUS_OK;
1071         }
1072
1073         /* Refuse the blob if it's bigger than 64k. */
1074         if (needed_len > 65536) {
1075                 DEBUG(2,("check_spnego_blob_complete: needed_len "
1076                         "too large (%u)\n",
1077                         (unsigned int)needed_len ));
1078                 return NT_STATUS_INVALID_PARAMETER;
1079         }
1080
1081         /* We must store this blob until complete. */
1082         if (!(pad = SMB_MALLOC_P(struct pending_auth_data))) {
1083                 return NT_STATUS_NO_MEMORY;
1084         }
1085         pad->needed_len = needed_len - pblob->length;
1086         pad->partial_data = data_blob(pblob->data, pblob->length);
1087         if (pad->partial_data.data == NULL) {
1088                 SAFE_FREE(pad);
1089                 return NT_STATUS_NO_MEMORY;
1090         }
1091         pad->smbpid = smbpid;
1092         pad->vuid = vuid;
1093         DLIST_ADD(pd_list, pad);
1094
1095         return NT_STATUS_MORE_PROCESSING_REQUIRED;
1096 }
1097
1098 /****************************************************************************
1099  Reply to a session setup command.
1100  conn POINTER CAN BE NULL HERE !
1101 ****************************************************************************/
1102
1103 static void reply_sesssetup_and_X_spnego(struct smb_request *req)
1104 {
1105         uint8 *p;
1106         DATA_BLOB blob1;
1107         size_t bufrem;
1108         fstring native_os, native_lanman, primary_domain;
1109         const char *p2;
1110         uint16 data_blob_len = SVAL(req->inbuf, smb_vwv7);
1111         enum remote_arch_types ra_type = get_remote_arch();
1112         int vuid = SVAL(req->inbuf,smb_uid);
1113         user_struct *vuser = NULL;
1114         NTSTATUS status = NT_STATUS_OK;
1115         uint16 smbpid = req->smbpid;
1116         uint16 smb_flag2 = req->flags2;
1117
1118         DEBUG(3,("Doing spnego session setup\n"));
1119
1120         if (global_client_caps == 0) {
1121                 global_client_caps = IVAL(req->inbuf,smb_vwv10);
1122
1123                 if (!(global_client_caps & CAP_STATUS32)) {
1124                         remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1125                 }
1126
1127         }
1128
1129         p = (uint8 *)smb_buf(req->inbuf);
1130
1131         if (data_blob_len == 0) {
1132                 /* an invalid request */
1133                 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1134                 return;
1135         }
1136
1137         bufrem = smb_bufrem(req->inbuf, p);
1138         /* pull the spnego blob */
1139         blob1 = data_blob(p, MIN(bufrem, data_blob_len));
1140
1141 #if 0
1142         file_save("negotiate.dat", blob1.data, blob1.length);
1143 #endif
1144
1145         p2 = (char *)req->inbuf + smb_vwv13 + data_blob_len;
1146         p2 += srvstr_pull_buf(req->inbuf, smb_flag2, native_os, p2,
1147                               sizeof(native_os), STR_TERMINATE);
1148         p2 += srvstr_pull_buf(req->inbuf, smb_flag2, native_lanman, p2,
1149                               sizeof(native_lanman), STR_TERMINATE);
1150         p2 += srvstr_pull_buf(req->inbuf, smb_flag2, primary_domain, p2,
1151                               sizeof(primary_domain), STR_TERMINATE);
1152         DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
1153                 native_os, native_lanman, primary_domain));
1154
1155         if ( ra_type == RA_WIN2K ) {
1156                 /* Vista sets neither the OS or lanman strings */
1157
1158                 if ( !strlen(native_os) && !strlen(native_lanman) )
1159                         set_remote_arch(RA_VISTA);
1160
1161                 /* Windows 2003 doesn't set the native lanman string,
1162                    but does set primary domain which is a bug I think */
1163
1164                 if ( !strlen(native_lanman) ) {
1165                         ra_lanman_string( primary_domain );
1166                 } else {
1167                         ra_lanman_string( native_lanman );
1168                 }
1169         }
1170
1171         /* Did we get a valid vuid ? */
1172         if (!is_partial_auth_vuid(vuid)) {
1173                 /* No, then try and see if this is an intermediate sessionsetup
1174                  * for a large SPNEGO packet. */
1175                 struct pending_auth_data *pad = get_pending_auth_data(smbpid);
1176                 if (pad) {
1177                         DEBUG(10,("reply_sesssetup_and_X_spnego: found "
1178                                 "pending vuid %u\n",
1179                                 (unsigned int)pad->vuid ));
1180                         vuid = pad->vuid;
1181                 }
1182         }
1183
1184         /* Do we have a valid vuid now ? */
1185         if (!is_partial_auth_vuid(vuid)) {
1186                 /* No, start a new authentication setup. */
1187                 vuid = register_initial_vuid();
1188                 if (vuid == UID_FIELD_INVALID) {
1189                         data_blob_free(&blob1);
1190                         reply_nterror(req, nt_status_squash(
1191                                               NT_STATUS_INVALID_PARAMETER));
1192                         return;
1193                 }
1194         }
1195
1196         vuser = get_partial_auth_user_struct(vuid);
1197         /* This MUST be valid. */
1198         if (!vuser) {
1199                 smb_panic("reply_sesssetup_and_X_spnego: invalid vuid.");
1200         }
1201
1202         /* Large (greater than 4k) SPNEGO blobs are split into multiple
1203          * sessionsetup requests as the Windows limit on the security blob
1204          * field is 4k. Bug #4400. JRA.
1205          */
1206
1207         status = check_spnego_blob_complete(smbpid, vuid, &blob1);
1208         if (!NT_STATUS_IS_OK(status)) {
1209                 if (!NT_STATUS_EQUAL(status,
1210                                 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1211                         /* Real error - kill the intermediate vuid */
1212                         invalidate_vuid(vuid);
1213                 }
1214                 data_blob_free(&blob1);
1215                 reply_nterror(req, nt_status_squash(status));
1216                 return;
1217         }
1218
1219         if (blob1.data[0] == ASN1_APPLICATION(0)) {
1220
1221                 /* its a negTokenTarg packet */
1222
1223                 reply_spnego_negotiate(req, vuid, blob1,
1224                                        &vuser->auth_ntlmssp_state);
1225                 data_blob_free(&blob1);
1226                 return;
1227         }
1228
1229         if (blob1.data[0] == ASN1_CONTEXT(1)) {
1230
1231                 /* its a auth packet */
1232
1233                 reply_spnego_auth(req, vuid, blob1,
1234                                   &vuser->auth_ntlmssp_state);
1235                 data_blob_free(&blob1);
1236                 return;
1237         }
1238
1239         if (strncmp((char *)(blob1.data), "NTLMSSP", 7) == 0) {
1240                 DATA_BLOB chal;
1241
1242                 if (!vuser->auth_ntlmssp_state) {
1243                         status = auth_ntlmssp_start(&vuser->auth_ntlmssp_state);
1244                         if (!NT_STATUS_IS_OK(status)) {
1245                                 /* Kill the intermediate vuid */
1246                                 invalidate_vuid(vuid);
1247                                 data_blob_free(&blob1);
1248                                 reply_nterror(req, nt_status_squash(status));
1249                                 return;
1250                         }
1251                 }
1252
1253                 status = auth_ntlmssp_update(vuser->auth_ntlmssp_state,
1254                                                 blob1, &chal);
1255
1256                 data_blob_free(&blob1);
1257
1258                 reply_spnego_ntlmssp(req, vuid,
1259                                      &vuser->auth_ntlmssp_state,
1260                                      &chal, status, False);
1261                 data_blob_free(&chal);
1262                 return;
1263         }
1264
1265         /* what sort of packet is this? */
1266         DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
1267
1268         data_blob_free(&blob1);
1269
1270         reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1271 }
1272
1273 /****************************************************************************
1274  On new VC == 0, shutdown *all* old connections and users.
1275  It seems that only NT4.x does this. At W2K and above (XP etc.).
1276  a new session setup with VC==0 is ignored.
1277 ****************************************************************************/
1278
1279 static int shutdown_other_smbds(struct db_record *rec,
1280                                 const struct connections_key *key,
1281                                 const struct connections_data *crec,
1282                                 void *private_data)
1283 {
1284         const char *ip = (const char *)private_data;
1285
1286         if (!process_exists(crec->pid)) {
1287                 return 0;
1288         }
1289
1290         if (procid_is_me(&crec->pid)) {
1291                 return 0;
1292         }
1293
1294         if (strcmp(ip, crec->addr) != 0) {
1295                 return 0;
1296         }
1297
1298         messaging_send(smbd_messaging_context(), crec->pid, MSG_SHUTDOWN,
1299                        &data_blob_null);
1300         return 0;
1301 }
1302
1303 static void setup_new_vc_session(void)
1304 {
1305         char addr[INET6_ADDRSTRLEN];
1306
1307         DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x "
1308                 "compatible we would close all old resources.\n"));
1309 #if 0
1310         conn_close_all();
1311         invalidate_all_vuids();
1312 #endif
1313         if (lp_reset_on_zero_vc()) {
1314                 connections_forall(shutdown_other_smbds,
1315                         CONST_DISCARD(void *,
1316                         client_addr(get_client_fd(),addr,sizeof(addr))));
1317         }
1318 }
1319
1320 /****************************************************************************
1321  Reply to a session setup command.
1322 ****************************************************************************/
1323
1324 void reply_sesssetup_and_X(struct smb_request *req)
1325 {
1326         int sess_vuid;
1327         int smb_bufsize;
1328         DATA_BLOB lm_resp;
1329         DATA_BLOB nt_resp;
1330         DATA_BLOB plaintext_password;
1331         fstring user;
1332         fstring sub_user; /* Sainitised username for substituion */
1333         fstring domain;
1334         fstring native_os;
1335         fstring native_lanman;
1336         fstring primary_domain;
1337         static bool done_sesssetup = False;
1338         auth_usersupplied_info *user_info = NULL;
1339         auth_serversupplied_info *server_info = NULL;
1340         uint16 smb_flag2 = req->flags2;
1341
1342         NTSTATUS nt_status;
1343
1344         bool doencrypt = global_encrypted_passwords_negotiated;
1345
1346         DATA_BLOB session_key;
1347
1348         START_PROFILE(SMBsesssetupX);
1349
1350         ZERO_STRUCT(lm_resp);
1351         ZERO_STRUCT(nt_resp);
1352         ZERO_STRUCT(plaintext_password);
1353
1354         DEBUG(3,("wct=%d flg2=0x%x\n", req->wct, req->flags2));
1355
1356         /* a SPNEGO session setup has 12 command words, whereas a normal
1357            NT1 session setup has 13. See the cifs spec. */
1358         if (req->wct == 12 &&
1359             (req->flags2 & FLAGS2_EXTENDED_SECURITY)) {
1360
1361                 if (!global_spnego_negotiated) {
1362                         DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt "
1363                                  "at SPNEGO session setup when it was not "
1364                                  "negotiated.\n"));
1365                         reply_nterror(req, nt_status_squash(
1366                                               NT_STATUS_LOGON_FAILURE));
1367                         END_PROFILE(SMBsesssetupX);
1368                         return;
1369                 }
1370
1371                 if (SVAL(req->inbuf,smb_vwv4) == 0) {
1372                         setup_new_vc_session();
1373                 }
1374
1375                 reply_sesssetup_and_X_spnego(req);
1376                 END_PROFILE(SMBsesssetupX);
1377                 return;
1378         }
1379
1380         smb_bufsize = SVAL(req->inbuf,smb_vwv2);
1381
1382         if (Protocol < PROTOCOL_NT1) {
1383                 uint16 passlen1 = SVAL(req->inbuf,smb_vwv7);
1384
1385                 /* Never do NT status codes with protocols before NT1 as we
1386                  * don't get client caps. */
1387                 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1388
1389                 if ((passlen1 > MAX_PASS_LEN)
1390                     || (passlen1 > smb_bufrem(req->inbuf,
1391                                               smb_buf(req->inbuf)))) {
1392                         reply_nterror(req, nt_status_squash(
1393                                               NT_STATUS_INVALID_PARAMETER));
1394                         END_PROFILE(SMBsesssetupX);
1395                         return;
1396                 }
1397
1398                 if (doencrypt) {
1399                         lm_resp = data_blob(smb_buf(req->inbuf), passlen1);
1400                 } else {
1401                         plaintext_password = data_blob(smb_buf(req->inbuf),
1402                                                        passlen1+1);
1403                         /* Ensure null termination */
1404                         plaintext_password.data[passlen1] = 0;
1405                 }
1406
1407                 srvstr_pull_buf(req->inbuf, req->flags2, user,
1408                                 smb_buf(req->inbuf)+passlen1, sizeof(user),
1409                                 STR_TERMINATE);
1410                 *domain = 0;
1411
1412         } else {
1413                 uint16 passlen1 = SVAL(req->inbuf,smb_vwv7);
1414                 uint16 passlen2 = SVAL(req->inbuf,smb_vwv8);
1415                 enum remote_arch_types ra_type = get_remote_arch();
1416                 char *p = smb_buf(req->inbuf);
1417                 char *save_p = smb_buf(req->inbuf);
1418                 uint16 byte_count;
1419
1420
1421                 if(global_client_caps == 0) {
1422                         global_client_caps = IVAL(req->inbuf,smb_vwv11);
1423
1424                         if (!(global_client_caps & CAP_STATUS32)) {
1425                                 remove_from_common_flags2(
1426                                                 FLAGS2_32_BIT_ERROR_CODES);
1427                         }
1428
1429                         /* client_caps is used as final determination if
1430                          * client is NT or Win95. This is needed to return
1431                          * the correct error codes in some circumstances.
1432                         */
1433
1434                         if(ra_type == RA_WINNT || ra_type == RA_WIN2K ||
1435                                         ra_type == RA_WIN95) {
1436                                 if(!(global_client_caps & (CAP_NT_SMBS|
1437                                                         CAP_STATUS32))) {
1438                                         set_remote_arch( RA_WIN95);
1439                                 }
1440                         }
1441                 }
1442
1443                 if (!doencrypt) {
1444                         /* both Win95 and WinNT stuff up the password
1445                          * lengths for non-encrypting systems. Uggh.
1446
1447                            if passlen1==24 its a win95 system, and its setting
1448                            the password length incorrectly. Luckily it still
1449                            works with the default code because Win95 will null
1450                            terminate the password anyway
1451
1452                            if passlen1>0 and passlen2>0 then maybe its a NT box
1453                            and its setting passlen2 to some random value which
1454                            really stuffs things up. we need to fix that one.  */
1455
1456                         if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 &&
1457                                         passlen2 != 1) {
1458                                 passlen2 = 0;
1459                         }
1460                 }
1461
1462                 /* check for nasty tricks */
1463                 if (passlen1 > MAX_PASS_LEN
1464                     || passlen1 > smb_bufrem(req->inbuf, p)) {
1465                         reply_nterror(req, nt_status_squash(
1466                                               NT_STATUS_INVALID_PARAMETER));
1467                         END_PROFILE(SMBsesssetupX);
1468                         return;
1469                 }
1470
1471                 if (passlen2 > MAX_PASS_LEN
1472                     || passlen2 > smb_bufrem(req->inbuf, p+passlen1)) {
1473                         reply_nterror(req, nt_status_squash(
1474                                               NT_STATUS_INVALID_PARAMETER));
1475                         END_PROFILE(SMBsesssetupX);
1476                         return;
1477                 }
1478
1479                 /* Save the lanman2 password and the NT md4 password. */
1480
1481                 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
1482                         doencrypt = False;
1483                 }
1484
1485                 if (doencrypt) {
1486                         lm_resp = data_blob(p, passlen1);
1487                         nt_resp = data_blob(p+passlen1, passlen2);
1488                 } else {
1489                         char *pass = NULL;
1490                         bool unic= smb_flag2 & FLAGS2_UNICODE_STRINGS;
1491
1492                         if (unic && (passlen2 == 0) && passlen1) {
1493                                 /* Only a ascii plaintext password was sent. */
1494                                 (void)srvstr_pull_talloc(talloc_tos(),
1495                                                         req->inbuf,
1496                                                         req->flags2,
1497                                                         &pass,
1498                                                         smb_buf(req->inbuf),
1499                                                         passlen1,
1500                                                         STR_TERMINATE|STR_ASCII);
1501                         } else {
1502                                 (void)srvstr_pull_talloc(talloc_tos(),
1503                                                         req->inbuf,
1504                                                         req->flags2,
1505                                                         &pass,
1506                                                         smb_buf(req->inbuf),
1507                                                         unic ? passlen2 : passlen1,
1508                                                         STR_TERMINATE);
1509                         }
1510                         if (!pass) {
1511                                 reply_nterror(req, nt_status_squash(
1512                                               NT_STATUS_INVALID_PARAMETER));
1513                                 END_PROFILE(SMBsesssetupX);
1514                                 return;
1515                         }
1516                         plaintext_password = data_blob(pass, strlen(pass)+1);
1517                 }
1518
1519                 p += passlen1 + passlen2;
1520                 p += srvstr_pull_buf(req->inbuf, req->flags2, user, p,
1521                                      sizeof(user), STR_TERMINATE);
1522                 p += srvstr_pull_buf(req->inbuf, req->flags2, domain, p,
1523                                      sizeof(domain), STR_TERMINATE);
1524                 p += srvstr_pull_buf(req->inbuf, req->flags2, native_os,
1525                                      p, sizeof(native_os), STR_TERMINATE);
1526                 p += srvstr_pull_buf(req->inbuf, req->flags2,
1527                                      native_lanman, p, sizeof(native_lanman),
1528                                      STR_TERMINATE);
1529
1530                 /* not documented or decoded by Ethereal but there is one more
1531                  * string in the extra bytes which is the same as the
1532                  * PrimaryDomain when using extended security.  Windows NT 4
1533                  * and 2003 use this string to store the native lanman string.
1534                  * Windows 9x does not include a string here at all so we have
1535                  * to check if we have any extra bytes left */
1536
1537                 byte_count = SVAL(req->inbuf, smb_vwv13);
1538                 if ( PTR_DIFF(p, save_p) < byte_count) {
1539                         p += srvstr_pull_buf(req->inbuf, req->flags2,
1540                                              primary_domain, p,
1541                                              sizeof(primary_domain),
1542                                              STR_TERMINATE);
1543                 } else {
1544                         fstrcpy( primary_domain, "null" );
1545                 }
1546
1547                 DEBUG(3,("Domain=[%s]  NativeOS=[%s] NativeLanMan=[%s] "
1548                         "PrimaryDomain=[%s]\n",
1549                         domain, native_os, native_lanman, primary_domain));
1550
1551                 if ( ra_type == RA_WIN2K ) {
1552                         if ( strlen(native_lanman) == 0 )
1553                                 ra_lanman_string( primary_domain );
1554                         else
1555                                 ra_lanman_string( native_lanman );
1556                 }
1557
1558         }
1559
1560         if (SVAL(req->inbuf,smb_vwv4) == 0) {
1561                 setup_new_vc_session();
1562         }
1563
1564         DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n",
1565                                 domain, user, get_remote_machine_name()));
1566
1567         if (*user) {
1568                 if (global_spnego_negotiated) {
1569
1570                         /* This has to be here, because this is a perfectly
1571                          * valid behaviour for guest logons :-( */
1572
1573                         DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt "
1574                                 "at 'normal' session setup after "
1575                                 "negotiating spnego.\n"));
1576                         reply_nterror(req, nt_status_squash(
1577                                               NT_STATUS_LOGON_FAILURE));
1578                         END_PROFILE(SMBsesssetupX);
1579                         return;
1580                 }
1581                 fstrcpy(sub_user, user);
1582         } else {
1583                 fstrcpy(sub_user, lp_guestaccount());
1584         }
1585
1586         sub_set_smb_name(sub_user);
1587
1588         reload_services(True);
1589
1590         if (lp_security() == SEC_SHARE) {
1591                 /* in share level we should ignore any passwords */
1592
1593                 data_blob_free(&lm_resp);
1594                 data_blob_free(&nt_resp);
1595                 data_blob_clear_free(&plaintext_password);
1596
1597                 map_username(sub_user);
1598                 add_session_user(sub_user);
1599                 add_session_workgroup(domain);
1600                 /* Then force it to null for the benfit of the code below */
1601                 *user = 0;
1602         }
1603
1604         if (!*user) {
1605
1606                 nt_status = check_guest_password(&server_info);
1607
1608         } else if (doencrypt) {
1609                 if (!negprot_global_auth_context) {
1610                         DEBUG(0, ("reply_sesssetup_and_X:  Attempted encrypted "
1611                                 "session setup without negprot denied!\n"));
1612                         reply_nterror(req, nt_status_squash(
1613                                               NT_STATUS_LOGON_FAILURE));
1614                         END_PROFILE(SMBsesssetupX);
1615                         return;
1616                 }
1617                 nt_status = make_user_info_for_reply_enc(&user_info, user,
1618                                                 domain,
1619                                                 lm_resp, nt_resp);
1620                 if (NT_STATUS_IS_OK(nt_status)) {
1621                         nt_status = negprot_global_auth_context->check_ntlm_password(
1622                                         negprot_global_auth_context,
1623                                         user_info,
1624                                         &server_info);
1625                 }
1626         } else {
1627                 struct auth_context *plaintext_auth_context = NULL;
1628                 const uint8 *chal;
1629
1630                 nt_status = make_auth_context_subsystem(
1631                                 &plaintext_auth_context);
1632
1633                 if (NT_STATUS_IS_OK(nt_status)) {
1634                         chal = plaintext_auth_context->get_ntlm_challenge(
1635                                         plaintext_auth_context);
1636
1637                         if (!make_user_info_for_reply(&user_info,
1638                                                       user, domain, chal,
1639                                                       plaintext_password)) {
1640                                 nt_status = NT_STATUS_NO_MEMORY;
1641                         }
1642
1643                         if (NT_STATUS_IS_OK(nt_status)) {
1644                                 nt_status = plaintext_auth_context->check_ntlm_password(
1645                                                 plaintext_auth_context,
1646                                                 user_info,
1647                                                 &server_info);
1648
1649                                 (plaintext_auth_context->free)(
1650                                                 &plaintext_auth_context);
1651                         }
1652                 }
1653         }
1654
1655         free_user_info(&user_info);
1656
1657         if (!NT_STATUS_IS_OK(nt_status)) {
1658                 nt_status = do_map_to_guest(nt_status, &server_info,
1659                                 user, domain);
1660         }
1661
1662         if (!NT_STATUS_IS_OK(nt_status)) {
1663                 data_blob_free(&nt_resp);
1664                 data_blob_free(&lm_resp);
1665                 data_blob_clear_free(&plaintext_password);
1666                 reply_nterror(req, nt_status_squash(nt_status));
1667                 END_PROFILE(SMBsesssetupX);
1668                 return;
1669         }
1670
1671         /* Ensure we can't possible take a code path leading to a
1672          * null defref. */
1673         if (!server_info) {
1674                 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1675                 END_PROFILE(SMBsesssetupX);
1676                 return;
1677         }
1678
1679         nt_status = create_local_token(server_info);
1680         if (!NT_STATUS_IS_OK(nt_status)) {
1681                 DEBUG(10, ("create_local_token failed: %s\n",
1682                            nt_errstr(nt_status)));
1683                 data_blob_free(&nt_resp);
1684                 data_blob_free(&lm_resp);
1685                 data_blob_clear_free(&plaintext_password);
1686                 reply_nterror(req, nt_status_squash(nt_status));
1687                 END_PROFILE(SMBsesssetupX);
1688                 return;
1689         }
1690
1691         if (server_info->user_session_key.data) {
1692                 session_key = data_blob(server_info->user_session_key.data,
1693                                 server_info->user_session_key.length);
1694         } else {
1695                 session_key = data_blob_null;
1696         }
1697
1698         data_blob_clear_free(&plaintext_password);
1699
1700         /* it's ok - setup a reply */
1701         reply_outbuf(req, 3, 0);
1702         if (Protocol >= PROTOCOL_NT1) {
1703                 push_signature(&req->outbuf);
1704                 /* perhaps grab OS version here?? */
1705         }
1706
1707         if (server_info->guest) {
1708                 SSVAL(req->outbuf,smb_vwv2,1);
1709         }
1710
1711         /* register the name and uid as being validated, so further connections
1712            to a uid can get through without a password, on the same VC */
1713
1714         if (lp_security() == SEC_SHARE) {
1715                 sess_vuid = UID_FIELD_INVALID;
1716                 data_blob_free(&session_key);
1717                 TALLOC_FREE(server_info);
1718         } else {
1719                 /* Ignore the initial vuid. */
1720                 sess_vuid = register_initial_vuid();
1721                 if (sess_vuid == UID_FIELD_INVALID) {
1722                         data_blob_free(&nt_resp);
1723                         data_blob_free(&lm_resp);
1724                         data_blob_free(&session_key);
1725                         reply_nterror(req, nt_status_squash(
1726                                               NT_STATUS_LOGON_FAILURE));
1727                         END_PROFILE(SMBsesssetupX);
1728                         return;
1729                 }
1730                 /* register_existing_vuid keeps the server info */
1731                 sess_vuid = register_existing_vuid(sess_vuid,
1732                                         server_info,
1733                                         session_key,
1734                                         nt_resp.data ? nt_resp : lm_resp,
1735                                         sub_user);
1736                 if (sess_vuid == UID_FIELD_INVALID) {
1737                         data_blob_free(&nt_resp);
1738                         data_blob_free(&lm_resp);
1739                         data_blob_free(&session_key);
1740                         reply_nterror(req, nt_status_squash(
1741                                               NT_STATUS_LOGON_FAILURE));
1742                         END_PROFILE(SMBsesssetupX);
1743                         return;
1744                 }
1745
1746                 /* current_user_info is changed on new vuid */
1747                 reload_services( True );
1748
1749                 sessionsetup_start_signing_engine(server_info, req->inbuf);
1750         }
1751
1752         data_blob_free(&nt_resp);
1753         data_blob_free(&lm_resp);
1754
1755         SSVAL(req->outbuf,smb_uid,sess_vuid);
1756         SSVAL(req->inbuf,smb_uid,sess_vuid);
1757
1758         if (!done_sesssetup)
1759                 max_send = MIN(max_send,smb_bufsize);
1760
1761         done_sesssetup = True;
1762
1763         END_PROFILE(SMBsesssetupX);
1764         chain_reply(req);
1765         return;
1766 }