s3-smbd: use make_server_info_krb5()
[mat/samba.git] / source3 / smbd / sesssetup.c
1 /*
2    Unix SMB/CIFS implementation.
3    handle SMBsessionsetup
4    Copyright (C) Andrew Tridgell 1998-2001
5    Copyright (C) Andrew Bartlett      2001
6    Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002
7    Copyright (C) Luke Howard          2003
8    Copyright (C) Volker Lendecke      2007
9    Copyright (C) Jeremy Allison       2007
10
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 3 of the License, or
14    (at your option) any later version.
15
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20
21    You should have received a copy of the GNU General Public License
22    along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 */
24
25 #include "includes.h"
26 #include "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         unsigned char chal[8];
145
146         ZERO_STRUCT(chal);
147
148         DEBUG(3,("Got anonymous request\n"));
149
150         if (!NT_STATUS_IS_OK(nt_status = make_auth_context_fixed(&auth_context,
151                                         chal))) {
152                 return nt_status;
153         }
154
155         if (!make_user_info_guest(&user_info)) {
156                 TALLOC_FREE(auth_context);
157                 return NT_STATUS_NO_MEMORY;
158         }
159
160         nt_status = auth_context->check_ntlm_password(auth_context,
161                                                 user_info,
162                                                 server_info);
163         TALLOC_FREE(auth_context);
164         free_user_info(&user_info);
165         return nt_status;
166 }
167
168
169 #ifdef HAVE_KRB5
170
171 #if 0
172 /* Experiment that failed. See "only happens with a KDC" comment below. */
173 /****************************************************************************
174  Cerate a clock skew error blob for a Windows client.
175 ****************************************************************************/
176
177 static bool make_krb5_skew_error(DATA_BLOB *pblob_out)
178 {
179         krb5_context context = NULL;
180         krb5_error_code kerr = 0;
181         krb5_data reply;
182         krb5_principal host_princ = NULL;
183         char *host_princ_s = NULL;
184         bool ret = False;
185
186         *pblob_out = data_blob_null;
187
188         initialize_krb5_error_table();
189         kerr = krb5_init_context(&context);
190         if (kerr) {
191                 return False;
192         }
193         /* Create server principal. */
194         asprintf(&host_princ_s, "%s$@%s", global_myname(), lp_realm());
195         if (!host_princ_s) {
196                 goto out;
197         }
198         strlower_m(host_princ_s);
199
200         kerr = smb_krb5_parse_name(context, host_princ_s, &host_princ);
201         if (kerr) {
202                 DEBUG(10,("make_krb5_skew_error: smb_krb5_parse_name failed "
203                         "for name %s: Error %s\n",
204                         host_princ_s, error_message(kerr) ));
205                 goto out;
206         }
207
208         kerr = smb_krb5_mk_error(context, KRB5KRB_AP_ERR_SKEW,
209                         host_princ, &reply);
210         if (kerr) {
211                 DEBUG(10,("make_krb5_skew_error: smb_krb5_mk_error "
212                         "failed: Error %s\n",
213                         error_message(kerr) ));
214                 goto out;
215         }
216
217         *pblob_out = data_blob(reply.data, reply.length);
218         kerberos_free_data_contents(context,&reply);
219         ret = True;
220
221   out:
222
223         if (host_princ_s) {
224                 SAFE_FREE(host_princ_s);
225         }
226         if (host_princ) {
227                 krb5_free_principal(context, host_princ);
228         }
229         krb5_free_context(context);
230         return ret;
231 }
232 #endif
233
234 /****************************************************************************
235  Reply to a session setup spnego negotiate packet for kerberos.
236 ****************************************************************************/
237
238 static void reply_spnego_kerberos(struct smb_request *req,
239                                   DATA_BLOB *secblob,
240                                   const char *mechOID,
241                                   uint16 vuid,
242                                   bool *p_invalidate_vuid)
243 {
244         TALLOC_CTX *mem_ctx;
245         DATA_BLOB ticket;
246         struct passwd *pw;
247         int sess_vuid = req->vuid;
248         NTSTATUS ret = NT_STATUS_OK;
249         DATA_BLOB ap_rep, ap_rep_wrapped, response;
250         struct auth_serversupplied_info *server_info = NULL;
251         DATA_BLOB session_key = data_blob_null;
252         uint8 tok_id[2];
253         DATA_BLOB nullblob = data_blob_null;
254         bool map_domainuser_to_guest = False;
255         bool username_was_mapped;
256         struct PAC_LOGON_INFO *logon_info = NULL;
257         struct smbd_server_connection *sconn = req->sconn;
258         char *principal;
259         char *user;
260         char *domain;
261         char *real_username;
262
263         ZERO_STRUCT(ticket);
264         ZERO_STRUCT(ap_rep);
265         ZERO_STRUCT(ap_rep_wrapped);
266         ZERO_STRUCT(response);
267
268         /* Normally we will always invalidate the intermediate vuid. */
269         *p_invalidate_vuid = True;
270
271         mem_ctx = talloc_init("reply_spnego_kerberos");
272         if (mem_ctx == NULL) {
273                 reply_nterror(req, nt_status_squash(NT_STATUS_NO_MEMORY));
274                 return;
275         }
276
277         if (!spnego_parse_krb5_wrap(mem_ctx, *secblob, &ticket, tok_id)) {
278                 talloc_destroy(mem_ctx);
279                 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
280                 return;
281         }
282
283         ret = ads_verify_ticket(mem_ctx, lp_realm(), 0, &ticket,
284                                 &principal, &logon_info, &ap_rep,
285                                 &session_key, True);
286
287         data_blob_free(&ticket);
288
289         if (!NT_STATUS_IS_OK(ret)) {
290 #if 0
291                 /* Experiment that failed.
292                  * See "only happens with a KDC" comment below. */
293
294                 if (NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
295
296                         /*
297                          * Windows in this case returns
298                          * NT_STATUS_MORE_PROCESSING_REQUIRED
299                          * with a negTokenTarg blob containing an krb5_error
300                          * struct ASN1 encoded containing KRB5KRB_AP_ERR_SKEW.
301                          * The client then fixes its clock and continues rather
302                          * than giving an error. JRA.
303                          * -- Looks like this only happens with a KDC. JRA.
304                          */
305
306                         bool ok = make_krb5_skew_error(&ap_rep);
307                         if (!ok) {
308                                 talloc_destroy(mem_ctx);
309                                 return ERROR_NT(nt_status_squash(
310                                                 NT_STATUS_LOGON_FAILURE));
311                         }
312                         ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep,
313                                         TOK_ID_KRB_ERROR);
314                         response = spnego_gen_auth_response(&ap_rep_wrapped,
315                                         ret, OID_KERBEROS5_OLD);
316                         reply_sesssetup_blob(conn, inbuf, outbuf, response,
317                                         NT_STATUS_MORE_PROCESSING_REQUIRED);
318
319                         /*
320                          * In this one case we don't invalidate the
321                          * intermediate vuid as we're expecting the client
322                          * to re-use it for the next sessionsetupX packet. JRA.
323                          */
324
325                         *p_invalidate_vuid = False;
326
327                         data_blob_free(&ap_rep);
328                         data_blob_free(&ap_rep_wrapped);
329                         data_blob_free(&response);
330                         talloc_destroy(mem_ctx);
331                         return -1; /* already replied */
332                 }
333 #else
334                 if (!NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
335                         ret = NT_STATUS_LOGON_FAILURE;
336                 }
337 #endif
338                 DEBUG(1,("Failed to verify incoming ticket with error %s!\n",
339                                 nt_errstr(ret)));
340                 talloc_destroy(mem_ctx);
341                 reply_nterror(req, nt_status_squash(ret));
342                 return;
343         }
344
345         ret = get_user_from_kerberos_info(talloc_tos(),
346                                           sconn->client_id.name,
347                                           principal, logon_info,
348                                           &username_was_mapped,
349                                           &map_domainuser_to_guest,
350                                           &user, &domain,
351                                           &real_username, &pw);
352         if (!NT_STATUS_IS_OK(ret)) {
353                 data_blob_free(&ap_rep);
354                 data_blob_free(&session_key);
355                 talloc_destroy(mem_ctx);
356                 reply_nterror(req,nt_status_squash(NT_STATUS_LOGON_FAILURE));
357                 return;
358         }
359
360         /* save the PAC data if we have it */
361         if (logon_info) {
362                 netsamlogon_cache_store(user, &logon_info->info3);
363         }
364
365         /* setup the string used by %U */
366         sub_set_smb_name(real_username);
367
368         /* reload services so that the new %U is taken into account */
369         reload_services(sconn->msg_ctx, sconn->sock, True);
370
371         ret = make_server_info_krb5(mem_ctx,
372                                     user, domain, real_username, pw,
373                                     logon_info, map_domainuser_to_guest,
374                                     &server_info);
375         if (!NT_STATUS_IS_OK(ret)) {
376                 DEBUG(1, ("make_server_info_krb5 failed!\n"));
377                 data_blob_free(&ap_rep);
378                 data_blob_free(&session_key);
379                 TALLOC_FREE(mem_ctx);
380                 reply_nterror(req, nt_status_squash(ret));
381                 return;
382         }
383
384         server_info->nss_token |= username_was_mapped;
385
386         /* we need to build the token for the user. make_server_info_guest()
387            already does this */
388
389         if ( !server_info->ptok ) {
390                 ret = create_local_token( server_info );
391                 if ( !NT_STATUS_IS_OK(ret) ) {
392                         DEBUG(10,("failed to create local token: %s\n",
393                                 nt_errstr(ret)));
394                         data_blob_free(&ap_rep);
395                         data_blob_free(&session_key);
396                         TALLOC_FREE( mem_ctx );
397                         TALLOC_FREE( server_info );
398                         reply_nterror(req, nt_status_squash(ret));
399                         return;
400                 }
401         }
402
403         if (!is_partial_auth_vuid(sconn, sess_vuid)) {
404                 sess_vuid = register_initial_vuid(sconn);
405         }
406
407         data_blob_free(&server_info->user_session_key);
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 *server_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_server_info(talloc_tos(),
483                                         (*auth_ntlmssp_state), &server_info);
484         } else {
485                 /* Note that this server_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                                             &server_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                                            server_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 (server_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                 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                 /* In share level we should ignore any passwords */
1550
1551                 data_blob_free(&lm_resp);
1552                 data_blob_free(&nt_resp);
1553                 data_blob_clear_free(&plaintext_password);
1554
1555                 map_username(sub_user);
1556                 add_session_user(sconn, sub_user);
1557                 add_session_workgroup(sconn, domain);
1558                 /* Then force it to null for the benfit of the code below */
1559                 user = "";
1560         }
1561
1562         if (!*user) {
1563
1564                 nt_status = check_guest_password(&server_info);
1565
1566         } else if (doencrypt) {
1567                 struct auth_context *negprot_auth_context = NULL;
1568                 negprot_auth_context = sconn->smb1.negprot.auth_context;
1569                 if (!negprot_auth_context) {
1570                         DEBUG(0, ("reply_sesssetup_and_X:  Attempted encrypted "
1571                                 "session setup without negprot denied!\n"));
1572                         reply_nterror(req, nt_status_squash(
1573                                               NT_STATUS_LOGON_FAILURE));
1574                         END_PROFILE(SMBsesssetupX);
1575                         return;
1576                 }
1577                 nt_status = make_user_info_for_reply_enc(&user_info, user,
1578                                                 domain,
1579                                                 lm_resp, nt_resp);
1580                 if (NT_STATUS_IS_OK(nt_status)) {
1581                         nt_status = negprot_auth_context->check_ntlm_password(
1582                                         negprot_auth_context,
1583                                         user_info,
1584                                         &server_info);
1585                 }
1586         } else {
1587                 struct auth_context *plaintext_auth_context = NULL;
1588
1589                 nt_status = make_auth_context_subsystem(
1590                                 &plaintext_auth_context);
1591
1592                 if (NT_STATUS_IS_OK(nt_status)) {
1593                         uint8_t chal[8];
1594
1595                         plaintext_auth_context->get_ntlm_challenge(
1596                                         plaintext_auth_context, chal);
1597
1598                         if (!make_user_info_for_reply(&user_info,
1599                                                       user, domain, chal,
1600                                                       plaintext_password)) {
1601                                 nt_status = NT_STATUS_NO_MEMORY;
1602                         }
1603
1604                         if (NT_STATUS_IS_OK(nt_status)) {
1605                                 nt_status = plaintext_auth_context->check_ntlm_password(
1606                                                 plaintext_auth_context,
1607                                                 user_info,
1608                                                 &server_info);
1609
1610                                 TALLOC_FREE(plaintext_auth_context);
1611                         }
1612                 }
1613         }
1614
1615         free_user_info(&user_info);
1616
1617         if (!NT_STATUS_IS_OK(nt_status)) {
1618                 nt_status = do_map_to_guest(nt_status, &server_info,
1619                                 user, domain);
1620         }
1621
1622         if (!NT_STATUS_IS_OK(nt_status)) {
1623                 data_blob_free(&nt_resp);
1624                 data_blob_free(&lm_resp);
1625                 data_blob_clear_free(&plaintext_password);
1626                 reply_nterror(req, nt_status_squash(nt_status));
1627                 END_PROFILE(SMBsesssetupX);
1628                 return;
1629         }
1630
1631         /* Ensure we can't possible take a code path leading to a
1632          * null defref. */
1633         if (!server_info) {
1634                 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1635                 END_PROFILE(SMBsesssetupX);
1636                 return;
1637         }
1638
1639         if (!server_info->ptok) {
1640                 nt_status = create_local_token(server_info);
1641
1642                 if (!NT_STATUS_IS_OK(nt_status)) {
1643                         DEBUG(10, ("create_local_token failed: %s\n",
1644                                    nt_errstr(nt_status)));
1645                         data_blob_free(&nt_resp);
1646                         data_blob_free(&lm_resp);
1647                         data_blob_clear_free(&plaintext_password);
1648                         reply_nterror(req, nt_status_squash(nt_status));
1649                         END_PROFILE(SMBsesssetupX);
1650                         return;
1651                 }
1652         }
1653
1654         data_blob_clear_free(&plaintext_password);
1655
1656         /* it's ok - setup a reply */
1657         reply_outbuf(req, 3, 0);
1658         if (get_Protocol() >= PROTOCOL_NT1) {
1659                 push_signature(&req->outbuf);
1660                 /* perhaps grab OS version here?? */
1661         }
1662
1663         if (server_info->guest) {
1664                 SSVAL(req->outbuf,smb_vwv2,1);
1665         }
1666
1667         /* register the name and uid as being validated, so further connections
1668            to a uid can get through without a password, on the same VC */
1669
1670         if (lp_security() == SEC_SHARE) {
1671                 sess_vuid = UID_FIELD_INVALID;
1672                 TALLOC_FREE(server_info);
1673         } else {
1674                 /* Ignore the initial vuid. */
1675                 sess_vuid = register_initial_vuid(sconn);
1676                 if (sess_vuid == UID_FIELD_INVALID) {
1677                         data_blob_free(&nt_resp);
1678                         data_blob_free(&lm_resp);
1679                         reply_nterror(req, nt_status_squash(
1680                                               NT_STATUS_LOGON_FAILURE));
1681                         END_PROFILE(SMBsesssetupX);
1682                         return;
1683                 }
1684                 /* register_existing_vuid keeps the server info */
1685                 sess_vuid = register_existing_vuid(sconn, sess_vuid,
1686                                         server_info,
1687                                         nt_resp.data ? nt_resp : lm_resp,
1688                                         sub_user);
1689                 if (sess_vuid == UID_FIELD_INVALID) {
1690                         data_blob_free(&nt_resp);
1691                         data_blob_free(&lm_resp);
1692                         reply_nterror(req, nt_status_squash(
1693                                               NT_STATUS_LOGON_FAILURE));
1694                         END_PROFILE(SMBsesssetupX);
1695                         return;
1696                 }
1697
1698                 /* current_user_info is changed on new vuid */
1699                 reload_services(sconn->msg_ctx, sconn->sock, True);
1700         }
1701
1702         data_blob_free(&nt_resp);
1703         data_blob_free(&lm_resp);
1704
1705         SSVAL(req->outbuf,smb_uid,sess_vuid);
1706         SSVAL(req->inbuf,smb_uid,sess_vuid);
1707         req->vuid = sess_vuid;
1708
1709         if (!sconn->smb1.sessions.done_sesssetup) {
1710                 sconn->smb1.sessions.max_send =
1711                         MIN(sconn->smb1.sessions.max_send,smb_bufsize);
1712         }
1713         sconn->smb1.sessions.done_sesssetup = true;
1714
1715         END_PROFILE(SMBsesssetupX);
1716         chain_reply(req);
1717         return;
1718 }