source: trunk/server/source3/smbd/sesssetup.c@ 745

Last change on this file since 745 was 745, checked in by Silvan Scherrer, 13 years ago

Samba Server: updated trunk to 3.6.0

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