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