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