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