source: branches/samba-3.5.x/source3/smbd/sesssetup.c@ 791

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

Samba 3.5: Update trunk to 3.5.9

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