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