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