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

Last change on this file since 421 was 414, checked in by Herwig Bauernfeind, 15 years ago

Samba 3.5.0: Initial import

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