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

Last change on this file since 593 was 590, checked in by Herwig Bauernfeind, 14 years ago

Samba 3.5: Update trunk to 3.5.6

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