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