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