source: vendor/3.5.6/source3/smbd/sesssetup.c

Last change on this file was 587, checked in by Herwig Bauernfeind, 14 years ago

Samba 3.5: Update vendor to version 3.5.6

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