source: branches/samba-3.2.x/source/smbd/sesssetup.c@ 272

Last change on this file since 272 was 204, checked in by Herwig Bauernfeind, 16 years ago

Update 3.2 branch to 3.2.4

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