source: branches/samba-3.3.x/source/smbd/sesssetup.c@ 221

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

Update Samba 3.3 to 3.3.1

File size: 50.3 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(NULL, 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(NULL, 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 mapping 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(NULL, &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 server_info->nss_token |= username_was_mapped;
538
539 /* we need to build the token for the user. make_server_info_guest()
540 already does this */
541
542 if ( !server_info->ptok ) {
543 ret = create_local_token( server_info );
544 if ( !NT_STATUS_IS_OK(ret) ) {
545 DEBUG(10,("failed to create local token: %s\n",
546 nt_errstr(ret)));
547 SAFE_FREE(client);
548 data_blob_free(&ap_rep);
549 data_blob_free(&session_key);
550 TALLOC_FREE( mem_ctx );
551 TALLOC_FREE( server_info );
552 reply_nterror(req, nt_status_squash(ret));
553 return;
554 }
555 }
556
557 /* register_existing_vuid keeps the server info */
558 /* register_existing_vuid takes ownership of session_key on success,
559 * no need to free after this on success. A better interface would copy
560 * it.... */
561
562 if (!is_partial_auth_vuid(sess_vuid)) {
563 sess_vuid = register_initial_vuid();
564 }
565
566 data_blob_free(&server_info->user_session_key);
567 server_info->user_session_key = session_key;
568 session_key = data_blob_null;
569
570 sess_vuid = register_existing_vuid(sess_vuid,
571 server_info,
572 nullblob,
573 client);
574
575 SAFE_FREE(client);
576
577 reply_outbuf(req, 4, 0);
578 SSVAL(req->outbuf,smb_uid,sess_vuid);
579
580 if (sess_vuid == UID_FIELD_INVALID ) {
581 ret = NT_STATUS_LOGON_FAILURE;
582 } else {
583 /* current_user_info is changed on new vuid */
584 reload_services( True );
585
586 SSVAL(req->outbuf, smb_vwv3, 0);
587
588 if (server_info->guest) {
589 SSVAL(req->outbuf,smb_vwv2,1);
590 }
591
592 SSVAL(req->outbuf, smb_uid, sess_vuid);
593
594 sessionsetup_start_signing_engine(server_info, req->inbuf);
595 /* Successful logon. Keep this vuid. */
596 *p_invalidate_vuid = False;
597 }
598
599 /* wrap that up in a nice GSS-API wrapping */
600 if (NT_STATUS_IS_OK(ret)) {
601 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep,
602 TOK_ID_KRB_AP_REP);
603 } else {
604 ap_rep_wrapped = data_blob_null;
605 }
606 response = spnego_gen_auth_response(&ap_rep_wrapped, ret,
607 mechOID);
608 reply_sesssetup_blob(req, response, ret);
609
610 data_blob_free(&ap_rep);
611 data_blob_free(&ap_rep_wrapped);
612 data_blob_free(&response);
613 TALLOC_FREE(mem_ctx);
614}
615
616#endif
617
618/****************************************************************************
619 Send a session setup reply, wrapped in SPNEGO.
620 Get vuid and check first.
621 End the NTLMSSP exchange context if we are OK/complete fail
622 This should be split into two functions, one to handle each
623 leg of the NTLM auth steps.
624***************************************************************************/
625
626static void reply_spnego_ntlmssp(struct smb_request *req,
627 uint16 vuid,
628 AUTH_NTLMSSP_STATE **auth_ntlmssp_state,
629 DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status,
630 const char *OID,
631 bool wrap)
632{
633 DATA_BLOB response;
634 struct auth_serversupplied_info *server_info = NULL;
635
636 if (NT_STATUS_IS_OK(nt_status)) {
637 server_info = (*auth_ntlmssp_state)->server_info;
638 } else {
639 nt_status = do_map_to_guest(nt_status,
640 &server_info,
641 (*auth_ntlmssp_state)->ntlmssp_state->user,
642 (*auth_ntlmssp_state)->ntlmssp_state->domain);
643 }
644
645 reply_outbuf(req, 4, 0);
646
647 SSVAL(req->outbuf, smb_uid, vuid);
648
649 if (NT_STATUS_IS_OK(nt_status)) {
650 DATA_BLOB nullblob = data_blob_null;
651
652 if (!is_partial_auth_vuid(vuid)) {
653 nt_status = NT_STATUS_LOGON_FAILURE;
654 goto out;
655 }
656
657 data_blob_free(&server_info->user_session_key);
658 server_info->user_session_key =
659 data_blob_talloc(
660 server_info,
661 (*auth_ntlmssp_state)->ntlmssp_state->session_key.data,
662 (*auth_ntlmssp_state)->ntlmssp_state->session_key.length);
663
664 /* register_existing_vuid keeps the server info */
665 if (register_existing_vuid(vuid,
666 server_info, nullblob,
667 (*auth_ntlmssp_state)->ntlmssp_state->user) !=
668 vuid) {
669 nt_status = NT_STATUS_LOGON_FAILURE;
670 goto out;
671 }
672
673 (*auth_ntlmssp_state)->server_info = NULL;
674
675 /* current_user_info is changed on new vuid */
676 reload_services( True );
677
678 SSVAL(req->outbuf, smb_vwv3, 0);
679
680 if (server_info->guest) {
681 SSVAL(req->outbuf,smb_vwv2,1);
682 }
683
684 sessionsetup_start_signing_engine(server_info,
685 (uint8 *)req->inbuf);
686 }
687
688 out:
689
690 if (wrap) {
691 response = spnego_gen_auth_response(ntlmssp_blob,
692 nt_status, OID);
693 } else {
694 response = *ntlmssp_blob;
695 }
696
697 reply_sesssetup_blob(req, response, nt_status);
698 if (wrap) {
699 data_blob_free(&response);
700 }
701
702 /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
703 and the other end, that we are not finished yet. */
704
705 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
706 /* NB. This is *NOT* an error case. JRA */
707 auth_ntlmssp_end(auth_ntlmssp_state);
708 if (!NT_STATUS_IS_OK(nt_status)) {
709 /* Kill the intermediate vuid */
710 invalidate_vuid(vuid);
711 }
712 }
713}
714
715/****************************************************************************
716 Is this a krb5 mechanism ?
717****************************************************************************/
718
719NTSTATUS parse_spnego_mechanisms(DATA_BLOB blob_in,
720 DATA_BLOB *pblob_out,
721 char **kerb_mechOID)
722{
723 char *OIDs[ASN1_MAX_OIDS];
724 int i;
725 NTSTATUS ret = NT_STATUS_OK;
726
727 *kerb_mechOID = NULL;
728
729 /* parse out the OIDs and the first sec blob */
730 if (!parse_negTokenTarg(blob_in, OIDs, pblob_out)) {
731 return NT_STATUS_LOGON_FAILURE;
732 }
733
734 /* only look at the first OID for determining the mechToken --
735 according to RFC2478, we should choose the one we want
736 and renegotiate, but i smell a client bug here..
737
738 Problem observed when connecting to a member (samba box)
739 of an AD domain as a user in a Samba domain. Samba member
740 server sent back krb5/mskrb5/ntlmssp as mechtypes, but the
741 client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an
742 NTLMSSP mechtoken. --jerry */
743
744#ifdef HAVE_KRB5
745 if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||
746 strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
747 *kerb_mechOID = SMB_STRDUP(OIDs[0]);
748 if (*kerb_mechOID == NULL) {
749 ret = NT_STATUS_NO_MEMORY;
750 }
751 }
752#endif
753
754 for (i=0;OIDs[i];i++) {
755 DEBUG(5,("parse_spnego_mechanisms: Got OID %s\n", OIDs[i]));
756 free(OIDs[i]);
757 }
758 return ret;
759}
760
761/****************************************************************************
762 Fall back from krb5 to NTLMSSP.
763****************************************************************************/
764
765static void reply_spnego_downgrade_to_ntlmssp(struct smb_request *req,
766 uint16 vuid)
767{
768 DATA_BLOB response;
769
770 reply_outbuf(req, 4, 0);
771 SSVAL(req->outbuf,smb_uid,vuid);
772
773 DEBUG(3,("reply_spnego_downgrade_to_ntlmssp: Got krb5 ticket in SPNEGO "
774 "but set to downgrade to NTLMSSP\n"));
775
776 response = spnego_gen_auth_response(NULL,
777 NT_STATUS_MORE_PROCESSING_REQUIRED,
778 OID_NTLMSSP);
779 reply_sesssetup_blob(req, response, NT_STATUS_MORE_PROCESSING_REQUIRED);
780 data_blob_free(&response);
781}
782
783/****************************************************************************
784 Reply to a session setup spnego negotiate packet.
785****************************************************************************/
786
787static void reply_spnego_negotiate(struct smb_request *req,
788 uint16 vuid,
789 DATA_BLOB blob1,
790 AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
791{
792 DATA_BLOB secblob;
793 DATA_BLOB chal;
794 char *kerb_mech = NULL;
795 NTSTATUS status;
796
797 status = parse_spnego_mechanisms(blob1, &secblob, &kerb_mech);
798 if (!NT_STATUS_IS_OK(status)) {
799 /* Kill the intermediate vuid */
800 invalidate_vuid(vuid);
801 reply_nterror(req, nt_status_squash(status));
802 return;
803 }
804
805 DEBUG(3,("reply_spnego_negotiate: Got secblob of size %lu\n",
806 (unsigned long)secblob.length));
807
808#ifdef HAVE_KRB5
809 if (kerb_mech && ((lp_security()==SEC_ADS) ||
810 lp_use_kerberos_keytab()) ) {
811 bool destroy_vuid = True;
812 reply_spnego_kerberos(req, &secblob, kerb_mech,
813 vuid, &destroy_vuid);
814 data_blob_free(&secblob);
815 if (destroy_vuid) {
816 /* Kill the intermediate vuid */
817 invalidate_vuid(vuid);
818 }
819 SAFE_FREE(kerb_mech);
820 return;
821 }
822#endif
823
824 if (*auth_ntlmssp_state) {
825 auth_ntlmssp_end(auth_ntlmssp_state);
826 }
827
828 if (kerb_mech) {
829 data_blob_free(&secblob);
830 /* The mechtoken is a krb5 ticket, but
831 * we need to fall back to NTLM. */
832 reply_spnego_downgrade_to_ntlmssp(req, vuid);
833 SAFE_FREE(kerb_mech);
834 return;
835 }
836
837 status = auth_ntlmssp_start(auth_ntlmssp_state);
838 if (!NT_STATUS_IS_OK(status)) {
839 /* Kill the intermediate vuid */
840 invalidate_vuid(vuid);
841 reply_nterror(req, nt_status_squash(status));
842 return;
843 }
844
845 status = auth_ntlmssp_update(*auth_ntlmssp_state,
846 secblob, &chal);
847
848 data_blob_free(&secblob);
849
850 reply_spnego_ntlmssp(req, vuid, auth_ntlmssp_state,
851 &chal, status, OID_NTLMSSP, true);
852
853 data_blob_free(&chal);
854
855 /* already replied */
856 return;
857}
858
859/****************************************************************************
860 Reply to a session setup spnego auth packet.
861****************************************************************************/
862
863static void reply_spnego_auth(struct smb_request *req,
864 uint16 vuid,
865 DATA_BLOB blob1,
866 AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
867{
868 DATA_BLOB auth = data_blob_null;
869 DATA_BLOB auth_reply = data_blob_null;
870 DATA_BLOB secblob = data_blob_null;
871 NTSTATUS status = NT_STATUS_LOGON_FAILURE;
872
873 if (!spnego_parse_auth(blob1, &auth)) {
874#if 0
875 file_save("auth.dat", blob1.data, blob1.length);
876#endif
877 /* Kill the intermediate vuid */
878 invalidate_vuid(vuid);
879
880 reply_nterror(req, nt_status_squash(
881 NT_STATUS_LOGON_FAILURE));
882 return;
883 }
884
885 if (auth.data[0] == ASN1_APPLICATION(0)) {
886 /* Might be a second negTokenTarg packet */
887 char *kerb_mech = NULL;
888
889 status = parse_spnego_mechanisms(auth, &secblob, &kerb_mech);
890
891 if (!NT_STATUS_IS_OK(status)) {
892 /* Kill the intermediate vuid */
893 invalidate_vuid(vuid);
894 reply_nterror(req, nt_status_squash(status));
895 return;
896 }
897
898 DEBUG(3,("reply_spnego_auth: Got secblob of size %lu\n",
899 (unsigned long)secblob.length));
900#ifdef HAVE_KRB5
901 if (kerb_mech && ((lp_security()==SEC_ADS) ||
902 lp_use_kerberos_keytab()) ) {
903 bool destroy_vuid = True;
904 reply_spnego_kerberos(req, &secblob, kerb_mech,
905 vuid, &destroy_vuid);
906 data_blob_free(&secblob);
907 data_blob_free(&auth);
908 if (destroy_vuid) {
909 /* Kill the intermediate vuid */
910 invalidate_vuid(vuid);
911 }
912 SAFE_FREE(kerb_mech);
913 return;
914 }
915#endif
916 /* Can't blunder into NTLMSSP auth if we have
917 * a krb5 ticket. */
918
919 if (kerb_mech) {
920 /* Kill the intermediate vuid */
921 invalidate_vuid(vuid);
922 DEBUG(3,("reply_spnego_auth: network "
923 "misconfiguration, client sent us a "
924 "krb5 ticket and kerberos security "
925 "not enabled\n"));
926 reply_nterror(req, nt_status_squash(
927 NT_STATUS_LOGON_FAILURE));
928 SAFE_FREE(kerb_mech);
929 }
930 }
931
932 /* If we get here it wasn't a negTokenTarg auth packet. */
933 data_blob_free(&secblob);
934
935 if (!*auth_ntlmssp_state) {
936 status = auth_ntlmssp_start(auth_ntlmssp_state);
937 if (!NT_STATUS_IS_OK(status)) {
938 /* Kill the intermediate vuid */
939 invalidate_vuid(vuid);
940 reply_nterror(req, nt_status_squash(status));
941 return;
942 }
943 }
944
945 status = auth_ntlmssp_update(*auth_ntlmssp_state,
946 auth, &auth_reply);
947
948 data_blob_free(&auth);
949
950 /* Don't send the mechid as we've already sent this (RFC4178). */
951
952 reply_spnego_ntlmssp(req, vuid,
953 auth_ntlmssp_state,
954 &auth_reply, status, NULL, true);
955
956 data_blob_free(&auth_reply);
957
958 /* and tell smbd that we have already replied to this packet */
959 return;
960}
961
962/****************************************************************************
963 List to store partial SPNEGO auth fragments.
964****************************************************************************/
965
966static struct pending_auth_data *pd_list;
967
968/****************************************************************************
969 Delete an entry on the list.
970****************************************************************************/
971
972static void delete_partial_auth(struct pending_auth_data *pad)
973{
974 if (!pad) {
975 return;
976 }
977 DLIST_REMOVE(pd_list, pad);
978 data_blob_free(&pad->partial_data);
979 SAFE_FREE(pad);
980}
981
982/****************************************************************************
983 Search for a partial SPNEGO auth fragment matching an smbpid.
984****************************************************************************/
985
986static struct pending_auth_data *get_pending_auth_data(uint16 smbpid)
987{
988 struct pending_auth_data *pad;
989
990 for (pad = pd_list; pad; pad = pad->next) {
991 if (pad->smbpid == smbpid) {
992 break;
993 }
994 }
995 return pad;
996}
997
998/****************************************************************************
999 Check the size of an SPNEGO blob. If we need more return
1000 NT_STATUS_MORE_PROCESSING_REQUIRED, else return NT_STATUS_OK. Don't allow
1001 the blob to be more than 64k.
1002****************************************************************************/
1003
1004static NTSTATUS check_spnego_blob_complete(uint16 smbpid, uint16 vuid,
1005 DATA_BLOB *pblob)
1006{
1007 struct pending_auth_data *pad = NULL;
1008 ASN1_DATA data;
1009 size_t needed_len = 0;
1010
1011 pad = get_pending_auth_data(smbpid);
1012
1013 /* Ensure we have some data. */
1014 if (pblob->length == 0) {
1015 /* Caller can cope. */
1016 DEBUG(2,("check_spnego_blob_complete: zero blob length !\n"));
1017 delete_partial_auth(pad);
1018 return NT_STATUS_OK;
1019 }
1020
1021 /* Were we waiting for more data ? */
1022 if (pad) {
1023 DATA_BLOB tmp_blob;
1024 size_t copy_len = MIN(65536, pblob->length);
1025
1026 /* Integer wrap paranoia.... */
1027
1028 if (pad->partial_data.length + copy_len <
1029 pad->partial_data.length ||
1030 pad->partial_data.length + copy_len < copy_len) {
1031
1032 DEBUG(2,("check_spnego_blob_complete: integer wrap "
1033 "pad->partial_data.length = %u, "
1034 "copy_len = %u\n",
1035 (unsigned int)pad->partial_data.length,
1036 (unsigned int)copy_len ));
1037
1038 delete_partial_auth(pad);
1039 return NT_STATUS_INVALID_PARAMETER;
1040 }
1041
1042 DEBUG(10,("check_spnego_blob_complete: "
1043 "pad->partial_data.length = %u, "
1044 "pad->needed_len = %u, "
1045 "copy_len = %u, "
1046 "pblob->length = %u,\n",
1047 (unsigned int)pad->partial_data.length,
1048 (unsigned int)pad->needed_len,
1049 (unsigned int)copy_len,
1050 (unsigned int)pblob->length ));
1051
1052 tmp_blob = data_blob(NULL,
1053 pad->partial_data.length + copy_len);
1054
1055 /* Concatenate the two (up to copy_len) bytes. */
1056 memcpy(tmp_blob.data,
1057 pad->partial_data.data,
1058 pad->partial_data.length);
1059 memcpy(tmp_blob.data + pad->partial_data.length,
1060 pblob->data,
1061 copy_len);
1062
1063 /* Replace the partial data. */
1064 data_blob_free(&pad->partial_data);
1065 pad->partial_data = tmp_blob;
1066 ZERO_STRUCT(tmp_blob);
1067
1068 /* Are we done ? */
1069 if (pblob->length >= pad->needed_len) {
1070 /* Yes, replace pblob. */
1071 data_blob_free(pblob);
1072 *pblob = pad->partial_data;
1073 ZERO_STRUCT(pad->partial_data);
1074 delete_partial_auth(pad);
1075 return NT_STATUS_OK;
1076 }
1077
1078 /* Still need more data. */
1079 pad->needed_len -= copy_len;
1080 return NT_STATUS_MORE_PROCESSING_REQUIRED;
1081 }
1082
1083 if ((pblob->data[0] != ASN1_APPLICATION(0)) &&
1084 (pblob->data[0] != ASN1_CONTEXT(1))) {
1085 /* Not something we can determine the
1086 * length of.
1087 */
1088 return NT_STATUS_OK;
1089 }
1090
1091 /* This is a new SPNEGO sessionsetup - see if
1092 * the data given in this blob is enough.
1093 */
1094
1095 asn1_load(&data, *pblob);
1096 asn1_start_tag(&data, pblob->data[0]);
1097 if (data.has_error || data.nesting == NULL) {
1098 asn1_free(&data);
1099 /* Let caller catch. */
1100 return NT_STATUS_OK;
1101 }
1102
1103 /* Integer wrap paranoia.... */
1104
1105 if (data.nesting->taglen + data.nesting->start < data.nesting->taglen ||
1106 data.nesting->taglen + data.nesting->start < data.nesting->start) {
1107
1108 DEBUG(2,("check_spnego_blob_complete: integer wrap "
1109 "data.nesting->taglen = %u, "
1110 "data.nesting->start = %u\n",
1111 (unsigned int)data.nesting->taglen,
1112 (unsigned int)data.nesting->start ));
1113
1114 asn1_free(&data);
1115 return NT_STATUS_INVALID_PARAMETER;
1116 }
1117
1118 /* Total length of the needed asn1 is the tag length
1119 * plus the current offset. */
1120
1121 needed_len = data.nesting->taglen + data.nesting->start;
1122 asn1_free(&data);
1123
1124 DEBUG(10,("check_spnego_blob_complete: needed_len = %u, "
1125 "pblob->length = %u\n",
1126 (unsigned int)needed_len,
1127 (unsigned int)pblob->length ));
1128
1129 if (needed_len <= pblob->length) {
1130 /* Nothing to do - blob is complete. */
1131 return NT_STATUS_OK;
1132 }
1133
1134 /* Refuse the blob if it's bigger than 64k. */
1135 if (needed_len > 65536) {
1136 DEBUG(2,("check_spnego_blob_complete: needed_len "
1137 "too large (%u)\n",
1138 (unsigned int)needed_len ));
1139 return NT_STATUS_INVALID_PARAMETER;
1140 }
1141
1142 /* We must store this blob until complete. */
1143 if (!(pad = SMB_MALLOC_P(struct pending_auth_data))) {
1144 return NT_STATUS_NO_MEMORY;
1145 }
1146 pad->needed_len = needed_len - pblob->length;
1147 pad->partial_data = data_blob(pblob->data, pblob->length);
1148 if (pad->partial_data.data == NULL) {
1149 SAFE_FREE(pad);
1150 return NT_STATUS_NO_MEMORY;
1151 }
1152 pad->smbpid = smbpid;
1153 pad->vuid = vuid;
1154 DLIST_ADD(pd_list, pad);
1155
1156 return NT_STATUS_MORE_PROCESSING_REQUIRED;
1157}
1158
1159/****************************************************************************
1160 Reply to a session setup command.
1161 conn POINTER CAN BE NULL HERE !
1162****************************************************************************/
1163
1164static void reply_sesssetup_and_X_spnego(struct smb_request *req)
1165{
1166 uint8 *p;
1167 DATA_BLOB blob1;
1168 size_t bufrem;
1169 fstring native_os, native_lanman, primary_domain;
1170 const char *p2;
1171 uint16 data_blob_len = SVAL(req->inbuf, smb_vwv7);
1172 enum remote_arch_types ra_type = get_remote_arch();
1173 int vuid = SVAL(req->inbuf,smb_uid);
1174 user_struct *vuser = NULL;
1175 NTSTATUS status = NT_STATUS_OK;
1176 uint16 smbpid = req->smbpid;
1177 uint16 smb_flag2 = req->flags2;
1178
1179 DEBUG(3,("Doing spnego session setup\n"));
1180
1181 if (global_client_caps == 0) {
1182 global_client_caps = IVAL(req->inbuf,smb_vwv10);
1183
1184 if (!(global_client_caps & CAP_STATUS32)) {
1185 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1186 }
1187
1188 }
1189
1190 p = (uint8 *)smb_buf(req->inbuf);
1191
1192 if (data_blob_len == 0) {
1193 /* an invalid request */
1194 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1195 return;
1196 }
1197
1198 bufrem = smb_bufrem(req->inbuf, p);
1199 /* pull the spnego blob */
1200 blob1 = data_blob(p, MIN(bufrem, data_blob_len));
1201
1202#if 0
1203 file_save("negotiate.dat", blob1.data, blob1.length);
1204#endif
1205
1206 p2 = (char *)req->inbuf + smb_vwv13 + data_blob_len;
1207 p2 += srvstr_pull_buf(req->inbuf, smb_flag2, native_os, p2,
1208 sizeof(native_os), STR_TERMINATE);
1209 p2 += srvstr_pull_buf(req->inbuf, smb_flag2, native_lanman, p2,
1210 sizeof(native_lanman), STR_TERMINATE);
1211 p2 += srvstr_pull_buf(req->inbuf, smb_flag2, primary_domain, p2,
1212 sizeof(primary_domain), STR_TERMINATE);
1213 DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
1214 native_os, native_lanman, primary_domain));
1215
1216 if ( ra_type == RA_WIN2K ) {
1217 /* Vista sets neither the OS or lanman strings */
1218
1219 if ( !strlen(native_os) && !strlen(native_lanman) )
1220 set_remote_arch(RA_VISTA);
1221
1222 /* Windows 2003 doesn't set the native lanman string,
1223 but does set primary domain which is a bug I think */
1224
1225 if ( !strlen(native_lanman) ) {
1226 ra_lanman_string( primary_domain );
1227 } else {
1228 ra_lanman_string( native_lanman );
1229 }
1230 }
1231
1232 /* Did we get a valid vuid ? */
1233 if (!is_partial_auth_vuid(vuid)) {
1234 /* No, then try and see if this is an intermediate sessionsetup
1235 * for a large SPNEGO packet. */
1236 struct pending_auth_data *pad = get_pending_auth_data(smbpid);
1237 if (pad) {
1238 DEBUG(10,("reply_sesssetup_and_X_spnego: found "
1239 "pending vuid %u\n",
1240 (unsigned int)pad->vuid ));
1241 vuid = pad->vuid;
1242 }
1243 }
1244
1245 /* Do we have a valid vuid now ? */
1246 if (!is_partial_auth_vuid(vuid)) {
1247 /* No, start a new authentication setup. */
1248 vuid = register_initial_vuid();
1249 if (vuid == UID_FIELD_INVALID) {
1250 data_blob_free(&blob1);
1251 reply_nterror(req, nt_status_squash(
1252 NT_STATUS_INVALID_PARAMETER));
1253 return;
1254 }
1255 }
1256
1257 vuser = get_partial_auth_user_struct(vuid);
1258 /* This MUST be valid. */
1259 if (!vuser) {
1260 smb_panic("reply_sesssetup_and_X_spnego: invalid vuid.");
1261 }
1262
1263 /* Large (greater than 4k) SPNEGO blobs are split into multiple
1264 * sessionsetup requests as the Windows limit on the security blob
1265 * field is 4k. Bug #4400. JRA.
1266 */
1267
1268 status = check_spnego_blob_complete(smbpid, vuid, &blob1);
1269 if (!NT_STATUS_IS_OK(status)) {
1270 if (!NT_STATUS_EQUAL(status,
1271 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1272 /* Real error - kill the intermediate vuid */
1273 invalidate_vuid(vuid);
1274 }
1275 data_blob_free(&blob1);
1276 reply_nterror(req, nt_status_squash(status));
1277 return;
1278 }
1279
1280 if (blob1.data[0] == ASN1_APPLICATION(0)) {
1281
1282 /* its a negTokenTarg packet */
1283
1284 reply_spnego_negotiate(req, vuid, blob1,
1285 &vuser->auth_ntlmssp_state);
1286 data_blob_free(&blob1);
1287 return;
1288 }
1289
1290 if (blob1.data[0] == ASN1_CONTEXT(1)) {
1291
1292 /* its a auth packet */
1293
1294 reply_spnego_auth(req, vuid, blob1,
1295 &vuser->auth_ntlmssp_state);
1296 data_blob_free(&blob1);
1297 return;
1298 }
1299
1300 if (strncmp((char *)(blob1.data), "NTLMSSP", 7) == 0) {
1301 DATA_BLOB chal;
1302
1303 if (!vuser->auth_ntlmssp_state) {
1304 status = auth_ntlmssp_start(&vuser->auth_ntlmssp_state);
1305 if (!NT_STATUS_IS_OK(status)) {
1306 /* Kill the intermediate vuid */
1307 invalidate_vuid(vuid);
1308 data_blob_free(&blob1);
1309 reply_nterror(req, nt_status_squash(status));
1310 return;
1311 }
1312 }
1313
1314 status = auth_ntlmssp_update(vuser->auth_ntlmssp_state,
1315 blob1, &chal);
1316
1317 data_blob_free(&blob1);
1318
1319 reply_spnego_ntlmssp(req, vuid,
1320 &vuser->auth_ntlmssp_state,
1321 &chal, status, OID_NTLMSSP, false);
1322 data_blob_free(&chal);
1323 return;
1324 }
1325
1326 /* what sort of packet is this? */
1327 DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
1328
1329 data_blob_free(&blob1);
1330
1331 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1332}
1333
1334/****************************************************************************
1335 On new VC == 0, shutdown *all* old connections and users.
1336 It seems that only NT4.x does this. At W2K and above (XP etc.).
1337 a new session setup with VC==0 is ignored.
1338****************************************************************************/
1339
1340static int shutdown_other_smbds(struct db_record *rec,
1341 const struct connections_key *key,
1342 const struct connections_data *crec,
1343 void *private_data)
1344{
1345 const char *ip = (const char *)private_data;
1346
1347 if (!process_exists(crec->pid)) {
1348 return 0;
1349 }
1350
1351 if (procid_is_me(&crec->pid)) {
1352 return 0;
1353 }
1354
1355 if (strcmp(ip, crec->addr) != 0) {
1356 return 0;
1357 }
1358
1359 DEBUG(0,("shutdown_other_smbds: shutting down pid %u "
1360 "(IP %s)\n", (unsigned int)procid_to_pid(&crec->pid), ip));
1361
1362 messaging_send(smbd_messaging_context(), crec->pid, MSG_SHUTDOWN,
1363 &data_blob_null);
1364 return 0;
1365}
1366
1367static void setup_new_vc_session(void)
1368{
1369 char addr[INET6_ADDRSTRLEN];
1370
1371 DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x "
1372 "compatible we would close all old resources.\n"));
1373#if 0
1374 conn_close_all();
1375 invalidate_all_vuids();
1376#endif
1377 if (lp_reset_on_zero_vc()) {
1378 connections_forall(shutdown_other_smbds,
1379 CONST_DISCARD(void *,
1380 client_addr(get_client_fd(),addr,sizeof(addr))));
1381 }
1382}
1383
1384/****************************************************************************
1385 Reply to a session setup command.
1386****************************************************************************/
1387
1388void reply_sesssetup_and_X(struct smb_request *req)
1389{
1390 int sess_vuid;
1391 int smb_bufsize;
1392 DATA_BLOB lm_resp;
1393 DATA_BLOB nt_resp;
1394 DATA_BLOB plaintext_password;
1395 fstring user;
1396 fstring sub_user; /* Sainitised username for substituion */
1397 fstring domain;
1398 fstring native_os;
1399 fstring native_lanman;
1400 fstring primary_domain;
1401 static bool done_sesssetup = False;
1402 auth_usersupplied_info *user_info = NULL;
1403 auth_serversupplied_info *server_info = NULL;
1404 uint16 smb_flag2 = req->flags2;
1405
1406 NTSTATUS nt_status;
1407
1408 bool doencrypt = global_encrypted_passwords_negotiated;
1409
1410 START_PROFILE(SMBsesssetupX);
1411
1412 ZERO_STRUCT(lm_resp);
1413 ZERO_STRUCT(nt_resp);
1414 ZERO_STRUCT(plaintext_password);
1415
1416 DEBUG(3,("wct=%d flg2=0x%x\n", req->wct, req->flags2));
1417
1418 /* a SPNEGO session setup has 12 command words, whereas a normal
1419 NT1 session setup has 13. See the cifs spec. */
1420 if (req->wct == 12 &&
1421 (req->flags2 & FLAGS2_EXTENDED_SECURITY)) {
1422
1423 if (!global_spnego_negotiated) {
1424 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt "
1425 "at SPNEGO session setup when it was not "
1426 "negotiated.\n"));
1427 reply_nterror(req, nt_status_squash(
1428 NT_STATUS_LOGON_FAILURE));
1429 END_PROFILE(SMBsesssetupX);
1430 return;
1431 }
1432
1433 if (SVAL(req->inbuf,smb_vwv4) == 0) {
1434 setup_new_vc_session();
1435 }
1436
1437 reply_sesssetup_and_X_spnego(req);
1438 END_PROFILE(SMBsesssetupX);
1439 return;
1440 }
1441
1442 smb_bufsize = SVAL(req->inbuf,smb_vwv2);
1443
1444 if (Protocol < PROTOCOL_NT1) {
1445 uint16 passlen1 = SVAL(req->inbuf,smb_vwv7);
1446
1447 /* Never do NT status codes with protocols before NT1 as we
1448 * don't get client caps. */
1449 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1450
1451 if ((passlen1 > MAX_PASS_LEN)
1452 || (passlen1 > smb_bufrem(req->inbuf,
1453 smb_buf(req->inbuf)))) {
1454 reply_nterror(req, nt_status_squash(
1455 NT_STATUS_INVALID_PARAMETER));
1456 END_PROFILE(SMBsesssetupX);
1457 return;
1458 }
1459
1460 if (doencrypt) {
1461 lm_resp = data_blob(smb_buf(req->inbuf), passlen1);
1462 } else {
1463 plaintext_password = data_blob(smb_buf(req->inbuf),
1464 passlen1+1);
1465 /* Ensure null termination */
1466 plaintext_password.data[passlen1] = 0;
1467 }
1468
1469 srvstr_pull_buf(req->inbuf, req->flags2, user,
1470 smb_buf(req->inbuf)+passlen1, sizeof(user),
1471 STR_TERMINATE);
1472 *domain = 0;
1473
1474 } else {
1475 uint16 passlen1 = SVAL(req->inbuf,smb_vwv7);
1476 uint16 passlen2 = SVAL(req->inbuf,smb_vwv8);
1477 enum remote_arch_types ra_type = get_remote_arch();
1478 char *p = smb_buf(req->inbuf);
1479 char *save_p = smb_buf(req->inbuf);
1480 uint16 byte_count;
1481
1482
1483 if(global_client_caps == 0) {
1484 global_client_caps = IVAL(req->inbuf,smb_vwv11);
1485
1486 if (!(global_client_caps & CAP_STATUS32)) {
1487 remove_from_common_flags2(
1488 FLAGS2_32_BIT_ERROR_CODES);
1489 }
1490
1491 /* client_caps is used as final determination if
1492 * client is NT or Win95. This is needed to return
1493 * the correct error codes in some circumstances.
1494 */
1495
1496 if(ra_type == RA_WINNT || ra_type == RA_WIN2K ||
1497 ra_type == RA_WIN95) {
1498 if(!(global_client_caps & (CAP_NT_SMBS|
1499 CAP_STATUS32))) {
1500 set_remote_arch( RA_WIN95);
1501 }
1502 }
1503 }
1504
1505 if (!doencrypt) {
1506 /* both Win95 and WinNT stuff up the password
1507 * lengths for non-encrypting systems. Uggh.
1508
1509 if passlen1==24 its a win95 system, and its setting
1510 the password length incorrectly. Luckily it still
1511 works with the default code because Win95 will null
1512 terminate the password anyway
1513
1514 if passlen1>0 and passlen2>0 then maybe its a NT box
1515 and its setting passlen2 to some random value which
1516 really stuffs things up. we need to fix that one. */
1517
1518 if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 &&
1519 passlen2 != 1) {
1520 passlen2 = 0;
1521 }
1522 }
1523
1524 /* check for nasty tricks */
1525 if (passlen1 > MAX_PASS_LEN
1526 || passlen1 > smb_bufrem(req->inbuf, p)) {
1527 reply_nterror(req, nt_status_squash(
1528 NT_STATUS_INVALID_PARAMETER));
1529 END_PROFILE(SMBsesssetupX);
1530 return;
1531 }
1532
1533 if (passlen2 > MAX_PASS_LEN
1534 || passlen2 > smb_bufrem(req->inbuf, p+passlen1)) {
1535 reply_nterror(req, nt_status_squash(
1536 NT_STATUS_INVALID_PARAMETER));
1537 END_PROFILE(SMBsesssetupX);
1538 return;
1539 }
1540
1541 /* Save the lanman2 password and the NT md4 password. */
1542
1543 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
1544 doencrypt = False;
1545 }
1546
1547 if (doencrypt) {
1548 lm_resp = data_blob(p, passlen1);
1549 nt_resp = data_blob(p+passlen1, passlen2);
1550 } else if (lp_security() != SEC_SHARE) {
1551 /*
1552 * In share level we should ignore any passwords, so
1553 * only read them if we're not.
1554 */
1555 char *pass = NULL;
1556 bool unic= smb_flag2 & FLAGS2_UNICODE_STRINGS;
1557
1558 if (unic && (passlen2 == 0) && passlen1) {
1559 /* Only a ascii plaintext password was sent. */
1560 (void)srvstr_pull_talloc(talloc_tos(),
1561 req->inbuf,
1562 req->flags2,
1563 &pass,
1564 smb_buf(req->inbuf),
1565 passlen1,
1566 STR_TERMINATE|STR_ASCII);
1567 } else {
1568 (void)srvstr_pull_talloc(talloc_tos(),
1569 req->inbuf,
1570 req->flags2,
1571 &pass,
1572 smb_buf(req->inbuf),
1573 unic ? passlen2 : passlen1,
1574 STR_TERMINATE);
1575 }
1576 if (!pass) {
1577 reply_nterror(req, nt_status_squash(
1578 NT_STATUS_INVALID_PARAMETER));
1579 END_PROFILE(SMBsesssetupX);
1580 return;
1581 }
1582 plaintext_password = data_blob(pass, strlen(pass)+1);
1583 }
1584
1585 p += passlen1 + passlen2;
1586 p += srvstr_pull_buf(req->inbuf, req->flags2, user, p,
1587 sizeof(user), STR_TERMINATE);
1588 p += srvstr_pull_buf(req->inbuf, req->flags2, domain, p,
1589 sizeof(domain), STR_TERMINATE);
1590 p += srvstr_pull_buf(req->inbuf, req->flags2, native_os,
1591 p, sizeof(native_os), STR_TERMINATE);
1592 p += srvstr_pull_buf(req->inbuf, req->flags2,
1593 native_lanman, p, sizeof(native_lanman),
1594 STR_TERMINATE);
1595
1596 /* not documented or decoded by Ethereal but there is one more
1597 * string in the extra bytes which is the same as the
1598 * PrimaryDomain when using extended security. Windows NT 4
1599 * and 2003 use this string to store the native lanman string.
1600 * Windows 9x does not include a string here at all so we have
1601 * to check if we have any extra bytes left */
1602
1603 byte_count = SVAL(req->inbuf, smb_vwv13);
1604 if ( PTR_DIFF(p, save_p) < byte_count) {
1605 p += srvstr_pull_buf(req->inbuf, req->flags2,
1606 primary_domain, p,
1607 sizeof(primary_domain),
1608 STR_TERMINATE);
1609 } else {
1610 fstrcpy( primary_domain, "null" );
1611 }
1612
1613 DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s] "
1614 "PrimaryDomain=[%s]\n",
1615 domain, native_os, native_lanman, primary_domain));
1616
1617 if ( ra_type == RA_WIN2K ) {
1618 if ( strlen(native_lanman) == 0 )
1619 ra_lanman_string( primary_domain );
1620 else
1621 ra_lanman_string( native_lanman );
1622 }
1623
1624 }
1625
1626 if (SVAL(req->inbuf,smb_vwv4) == 0) {
1627 setup_new_vc_session();
1628 }
1629
1630 DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n",
1631 domain, user, get_remote_machine_name()));
1632
1633 if (*user) {
1634 if (global_spnego_negotiated) {
1635
1636 /* This has to be here, because this is a perfectly
1637 * valid behaviour for guest logons :-( */
1638
1639 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt "
1640 "at 'normal' session setup after "
1641 "negotiating spnego.\n"));
1642 reply_nterror(req, nt_status_squash(
1643 NT_STATUS_LOGON_FAILURE));
1644 END_PROFILE(SMBsesssetupX);
1645 return;
1646 }
1647 fstrcpy(sub_user, user);
1648 } else {
1649 fstrcpy(sub_user, lp_guestaccount());
1650 }
1651
1652 sub_set_smb_name(sub_user);
1653
1654 reload_services(True);
1655
1656 if (lp_security() == SEC_SHARE) {
1657 /* In share level we should ignore any passwords */
1658
1659 data_blob_free(&lm_resp);
1660 data_blob_free(&nt_resp);
1661 data_blob_clear_free(&plaintext_password);
1662
1663 map_username(sub_user);
1664 add_session_user(sub_user);
1665 add_session_workgroup(domain);
1666 /* Then force it to null for the benfit of the code below */
1667 *user = 0;
1668 }
1669
1670 if (!*user) {
1671
1672 nt_status = check_guest_password(&server_info);
1673
1674 } else if (doencrypt) {
1675 if (!negprot_global_auth_context) {
1676 DEBUG(0, ("reply_sesssetup_and_X: Attempted encrypted "
1677 "session setup without negprot denied!\n"));
1678 reply_nterror(req, nt_status_squash(
1679 NT_STATUS_LOGON_FAILURE));
1680 END_PROFILE(SMBsesssetupX);
1681 return;
1682 }
1683 nt_status = make_user_info_for_reply_enc(&user_info, user,
1684 domain,
1685 lm_resp, nt_resp);
1686 if (NT_STATUS_IS_OK(nt_status)) {
1687 nt_status = negprot_global_auth_context->check_ntlm_password(
1688 negprot_global_auth_context,
1689 user_info,
1690 &server_info);
1691 }
1692 } else {
1693 struct auth_context *plaintext_auth_context = NULL;
1694 const uint8 *chal;
1695
1696 nt_status = make_auth_context_subsystem(
1697 &plaintext_auth_context);
1698
1699 if (NT_STATUS_IS_OK(nt_status)) {
1700 chal = plaintext_auth_context->get_ntlm_challenge(
1701 plaintext_auth_context);
1702
1703 if (!make_user_info_for_reply(&user_info,
1704 user, domain, chal,
1705 plaintext_password)) {
1706 nt_status = NT_STATUS_NO_MEMORY;
1707 }
1708
1709 if (NT_STATUS_IS_OK(nt_status)) {
1710 nt_status = plaintext_auth_context->check_ntlm_password(
1711 plaintext_auth_context,
1712 user_info,
1713 &server_info);
1714
1715 (plaintext_auth_context->free)(
1716 &plaintext_auth_context);
1717 }
1718 }
1719 }
1720
1721 free_user_info(&user_info);
1722
1723 if (!NT_STATUS_IS_OK(nt_status)) {
1724 nt_status = do_map_to_guest(nt_status, &server_info,
1725 user, domain);
1726 }
1727
1728 if (!NT_STATUS_IS_OK(nt_status)) {
1729 data_blob_free(&nt_resp);
1730 data_blob_free(&lm_resp);
1731 data_blob_clear_free(&plaintext_password);
1732 reply_nterror(req, nt_status_squash(nt_status));
1733 END_PROFILE(SMBsesssetupX);
1734 return;
1735 }
1736
1737 /* Ensure we can't possible take a code path leading to a
1738 * null defref. */
1739 if (!server_info) {
1740 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1741 END_PROFILE(SMBsesssetupX);
1742 return;
1743 }
1744
1745 if (!server_info->ptok) {
1746 nt_status = create_local_token(server_info);
1747
1748 if (!NT_STATUS_IS_OK(nt_status)) {
1749 DEBUG(10, ("create_local_token failed: %s\n",
1750 nt_errstr(nt_status)));
1751 data_blob_free(&nt_resp);
1752 data_blob_free(&lm_resp);
1753 data_blob_clear_free(&plaintext_password);
1754 reply_nterror(req, nt_status_squash(nt_status));
1755 END_PROFILE(SMBsesssetupX);
1756 return;
1757 }
1758 }
1759
1760 data_blob_clear_free(&plaintext_password);
1761
1762 /* it's ok - setup a reply */
1763 reply_outbuf(req, 3, 0);
1764 if (Protocol >= PROTOCOL_NT1) {
1765 push_signature(&req->outbuf);
1766 /* perhaps grab OS version here?? */
1767 }
1768
1769 if (server_info->guest) {
1770 SSVAL(req->outbuf,smb_vwv2,1);
1771 }
1772
1773 /* register the name and uid as being validated, so further connections
1774 to a uid can get through without a password, on the same VC */
1775
1776 if (lp_security() == SEC_SHARE) {
1777 sess_vuid = UID_FIELD_INVALID;
1778 TALLOC_FREE(server_info);
1779 } else {
1780 /* Ignore the initial vuid. */
1781 sess_vuid = register_initial_vuid();
1782 if (sess_vuid == UID_FIELD_INVALID) {
1783 data_blob_free(&nt_resp);
1784 data_blob_free(&lm_resp);
1785 reply_nterror(req, nt_status_squash(
1786 NT_STATUS_LOGON_FAILURE));
1787 END_PROFILE(SMBsesssetupX);
1788 return;
1789 }
1790 /* register_existing_vuid keeps the server info */
1791 sess_vuid = register_existing_vuid(sess_vuid,
1792 server_info,
1793 nt_resp.data ? nt_resp : lm_resp,
1794 sub_user);
1795 if (sess_vuid == UID_FIELD_INVALID) {
1796 data_blob_free(&nt_resp);
1797 data_blob_free(&lm_resp);
1798 reply_nterror(req, nt_status_squash(
1799 NT_STATUS_LOGON_FAILURE));
1800 END_PROFILE(SMBsesssetupX);
1801 return;
1802 }
1803
1804 /* current_user_info is changed on new vuid */
1805 reload_services( True );
1806
1807 sessionsetup_start_signing_engine(server_info, req->inbuf);
1808 }
1809
1810 data_blob_free(&nt_resp);
1811 data_blob_free(&lm_resp);
1812
1813 SSVAL(req->outbuf,smb_uid,sess_vuid);
1814 SSVAL(req->inbuf,smb_uid,sess_vuid);
1815
1816 if (!done_sesssetup)
1817 max_send = MIN(max_send,smb_bufsize);
1818
1819 done_sesssetup = True;
1820
1821 END_PROFILE(SMBsesssetupX);
1822 chain_reply(req);
1823 return;
1824}
Note: See TracBrowser for help on using the repository browser.