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