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