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