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