s3: async cli_list
[Samba/gbeck.git] / source3 / smbd / sesssetup.c
bloba476ed42ae7cd1f81132afbdf5394aef17e41ba6
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
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.
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.
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/>.
25 #include "includes.h"
26 #include "smbd/globals.h"
27 #include "../libcli/auth/spnego.h"
28 #include "../libcli/auth/ntlmssp.h"
29 #include "ntlmssp_wrap.h"
30 #include "librpc/gen_ndr/messaging.h"
31 #include "../librpc/gen_ndr/krb5pac.h"
32 #include "libads/kerberos_proto.h"
34 /* For split krb5 SPNEGO blobs. */
35 struct pending_auth_data {
36 struct pending_auth_data *prev, *next;
37 uint16 vuid; /* Tag for this entry. */
38 uint16 smbpid; /* Alternate tag for this entry. */
39 size_t needed_len;
40 DATA_BLOB partial_data;
44 on a logon error possibly map the error to success if "map to guest"
45 is set approriately
47 NTSTATUS do_map_to_guest(NTSTATUS status,
48 struct auth_serversupplied_info **server_info,
49 const char *user, const char *domain)
51 user = user ? user : "";
52 domain = domain ? domain : "";
54 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
55 if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) ||
56 (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) {
57 DEBUG(3,("No such user %s [%s] - using guest account\n",
58 user, domain));
59 status = make_server_info_guest(NULL, server_info);
63 if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
64 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) {
65 DEBUG(3,("Registered username %s for guest access\n",
66 user));
67 status = make_server_info_guest(NULL, server_info);
71 return status;
74 /****************************************************************************
75 Add the standard 'Samba' signature to the end of the session setup.
76 ****************************************************************************/
78 static int push_signature(uint8 **outbuf)
80 char *lanman;
81 int result, tmp;
83 result = 0;
85 tmp = message_push_string(outbuf, "Unix", STR_TERMINATE);
87 if (tmp == -1) return -1;
88 result += tmp;
90 if (asprintf(&lanman, "Samba %s", samba_version_string()) != -1) {
91 tmp = message_push_string(outbuf, lanman, STR_TERMINATE);
92 SAFE_FREE(lanman);
94 else {
95 tmp = message_push_string(outbuf, "Samba", STR_TERMINATE);
98 if (tmp == -1) return -1;
99 result += tmp;
101 tmp = message_push_string(outbuf, lp_workgroup(), STR_TERMINATE);
103 if (tmp == -1) return -1;
104 result += tmp;
106 return result;
109 /****************************************************************************
110 Send a security blob via a session setup reply.
111 ****************************************************************************/
113 static void reply_sesssetup_blob(struct smb_request *req,
114 DATA_BLOB blob,
115 NTSTATUS nt_status)
117 if (!NT_STATUS_IS_OK(nt_status) &&
118 !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
119 reply_nterror(req, nt_status_squash(nt_status));
120 return;
123 nt_status = nt_status_squash(nt_status);
124 SIVAL(req->outbuf, smb_rcls, NT_STATUS_V(nt_status));
125 SSVAL(req->outbuf, smb_vwv0, 0xFF); /* no chaining possible */
126 SSVAL(req->outbuf, smb_vwv3, blob.length);
128 if ((message_push_blob(&req->outbuf, blob) == -1)
129 || (push_signature(&req->outbuf) == -1)) {
130 reply_nterror(req, NT_STATUS_NO_MEMORY);
134 /****************************************************************************
135 Do a 'guest' logon, getting back the
136 ****************************************************************************/
138 static NTSTATUS check_guest_password(struct auth_serversupplied_info **server_info)
140 struct auth_context *auth_context;
141 struct auth_usersupplied_info *user_info = NULL;
143 NTSTATUS nt_status;
144 unsigned char chal[8];
146 ZERO_STRUCT(chal);
148 DEBUG(3,("Got anonymous request\n"));
150 if (!NT_STATUS_IS_OK(nt_status = make_auth_context_fixed(&auth_context,
151 chal))) {
152 return nt_status;
155 if (!make_user_info_guest(&user_info)) {
156 TALLOC_FREE(auth_context);
157 return NT_STATUS_NO_MEMORY;
160 nt_status = auth_context->check_ntlm_password(auth_context,
161 user_info,
162 server_info);
163 TALLOC_FREE(auth_context);
164 free_user_info(&user_info);
165 return nt_status;
169 #ifdef HAVE_KRB5
171 #if 0
172 /* Experiment that failed. See "only happens with a KDC" comment below. */
173 /****************************************************************************
174 Cerate a clock skew error blob for a Windows client.
175 ****************************************************************************/
177 static bool make_krb5_skew_error(DATA_BLOB *pblob_out)
179 krb5_context context = NULL;
180 krb5_error_code kerr = 0;
181 krb5_data reply;
182 krb5_principal host_princ = NULL;
183 char *host_princ_s = NULL;
184 bool ret = False;
186 *pblob_out = data_blob_null;
188 initialize_krb5_error_table();
189 kerr = krb5_init_context(&context);
190 if (kerr) {
191 return False;
193 /* Create server principal. */
194 asprintf(&host_princ_s, "%s$@%s", global_myname(), lp_realm());
195 if (!host_princ_s) {
196 goto out;
198 strlower_m(host_princ_s);
200 kerr = smb_krb5_parse_name(context, host_princ_s, &host_princ);
201 if (kerr) {
202 DEBUG(10,("make_krb5_skew_error: smb_krb5_parse_name failed "
203 "for name %s: Error %s\n",
204 host_princ_s, error_message(kerr) ));
205 goto out;
208 kerr = smb_krb5_mk_error(context, KRB5KRB_AP_ERR_SKEW,
209 host_princ, &reply);
210 if (kerr) {
211 DEBUG(10,("make_krb5_skew_error: smb_krb5_mk_error "
212 "failed: Error %s\n",
213 error_message(kerr) ));
214 goto out;
217 *pblob_out = data_blob(reply.data, reply.length);
218 kerberos_free_data_contents(context,&reply);
219 ret = True;
221 out:
223 if (host_princ_s) {
224 SAFE_FREE(host_princ_s);
226 if (host_princ) {
227 krb5_free_principal(context, host_princ);
229 krb5_free_context(context);
230 return ret;
232 #endif
234 /****************************************************************************
235 Reply to a session setup spnego negotiate packet for kerberos.
236 ****************************************************************************/
238 static void reply_spnego_kerberos(struct smb_request *req,
239 DATA_BLOB *secblob,
240 const char *mechOID,
241 uint16 vuid,
242 bool *p_invalidate_vuid)
244 TALLOC_CTX *mem_ctx;
245 DATA_BLOB ticket;
246 char *client, *p, *domain;
247 fstring netbios_domain_name;
248 struct passwd *pw;
249 fstring user;
250 int sess_vuid = req->vuid;
251 NTSTATUS ret = NT_STATUS_OK;
252 DATA_BLOB ap_rep, ap_rep_wrapped, response;
253 struct auth_serversupplied_info *server_info = NULL;
254 DATA_BLOB session_key = data_blob_null;
255 uint8 tok_id[2];
256 DATA_BLOB nullblob = data_blob_null;
257 fstring real_username;
258 bool map_domainuser_to_guest = False;
259 bool username_was_mapped;
260 struct PAC_LOGON_INFO *logon_info = NULL;
261 struct smbd_server_connection *sconn = req->sconn;
263 ZERO_STRUCT(ticket);
264 ZERO_STRUCT(ap_rep);
265 ZERO_STRUCT(ap_rep_wrapped);
266 ZERO_STRUCT(response);
268 /* Normally we will always invalidate the intermediate vuid. */
269 *p_invalidate_vuid = True;
271 mem_ctx = talloc_init("reply_spnego_kerberos");
272 if (mem_ctx == NULL) {
273 reply_nterror(req, nt_status_squash(NT_STATUS_NO_MEMORY));
274 return;
277 if (!spnego_parse_krb5_wrap(mem_ctx, *secblob, &ticket, tok_id)) {
278 talloc_destroy(mem_ctx);
279 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
280 return;
283 ret = ads_verify_ticket(mem_ctx, lp_realm(), 0, &ticket,
284 &client, &logon_info, &ap_rep,
285 &session_key, True);
287 data_blob_free(&ticket);
289 if (!NT_STATUS_IS_OK(ret)) {
290 #if 0
291 /* Experiment that failed.
292 * See "only happens with a KDC" comment below. */
294 if (NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
297 * Windows in this case returns
298 * NT_STATUS_MORE_PROCESSING_REQUIRED
299 * with a negTokenTarg blob containing an krb5_error
300 * struct ASN1 encoded containing KRB5KRB_AP_ERR_SKEW.
301 * The client then fixes its clock and continues rather
302 * than giving an error. JRA.
303 * -- Looks like this only happens with a KDC. JRA.
306 bool ok = make_krb5_skew_error(&ap_rep);
307 if (!ok) {
308 talloc_destroy(mem_ctx);
309 return ERROR_NT(nt_status_squash(
310 NT_STATUS_LOGON_FAILURE));
312 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep,
313 TOK_ID_KRB_ERROR);
314 response = spnego_gen_auth_response(&ap_rep_wrapped,
315 ret, OID_KERBEROS5_OLD);
316 reply_sesssetup_blob(conn, inbuf, outbuf, response,
317 NT_STATUS_MORE_PROCESSING_REQUIRED);
320 * In this one case we don't invalidate the
321 * intermediate vuid as we're expecting the client
322 * to re-use it for the next sessionsetupX packet. JRA.
325 *p_invalidate_vuid = False;
327 data_blob_free(&ap_rep);
328 data_blob_free(&ap_rep_wrapped);
329 data_blob_free(&response);
330 talloc_destroy(mem_ctx);
331 return -1; /* already replied */
333 #else
334 if (!NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
335 ret = NT_STATUS_LOGON_FAILURE;
337 #endif
338 DEBUG(1,("Failed to verify incoming ticket with error %s!\n",
339 nt_errstr(ret)));
340 talloc_destroy(mem_ctx);
341 reply_nterror(req, nt_status_squash(ret));
342 return;
345 DEBUG(3,("Ticket name is [%s]\n", client));
347 p = strchr_m(client, '@');
348 if (!p) {
349 DEBUG(3,("Doesn't look like a valid principal\n"));
350 data_blob_free(&ap_rep);
351 data_blob_free(&session_key);
352 talloc_destroy(mem_ctx);
353 reply_nterror(req,nt_status_squash(NT_STATUS_LOGON_FAILURE));
354 return;
357 *p = 0;
359 /* save the PAC data if we have it */
361 if (logon_info) {
362 netsamlogon_cache_store( client, &logon_info->info3 );
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;
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? */
380 domain = p+1;
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));
388 } else {
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. */
397 wbcErr wbc_status;
398 struct wbcDomainInfo *info = NULL;
400 DEBUG(10, ("Mapping [%s] to short name\n", domain));
402 wbc_status = wbcDomainInfo(domain, &info);
404 if (WBC_ERROR_IS_OK(wbc_status)) {
406 fstrcpy(netbios_domain_name,
407 info->short_name);
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)));
418 fstr_sprintf(user, "%s%c%s", domain, *lp_winbind_separator(), client);
420 /* lookup the passwd struct, create a new user if necessary */
422 username_was_mapped = map_username(user);
424 pw = smb_getpwnam( mem_ctx, user, real_username, True );
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;
442 if (!pw) {
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 */
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 );
454 /* extra sanity check that the guest account is valid */
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;
468 /* setup the string used by %U */
470 sub_set_smb_name( real_username );
471 reload_services(sconn->msg_ctx, sconn->sock, True);
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() */
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;
491 } else {
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
497 struct samu *sampass;
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;
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 TALLOC_FREE(sampass);
514 } else {
516 * User not in passdb, make it up artificially
518 TALLOC_FREE(sampass);
519 DEBUG(10, ("didn't find user %s in passdb, calling "
520 "make_server_info_pw\n", real_username));
521 ret = make_server_info_pw(&server_info, real_username,
522 pw);
525 if ( !NT_STATUS_IS_OK(ret) ) {
526 DEBUG(1,("make_server_info_[sam|pw] failed: %s!\n",
527 nt_errstr(ret)));
528 data_blob_free(&ap_rep);
529 data_blob_free(&session_key);
530 TALLOC_FREE(mem_ctx);
531 reply_nterror(req, nt_status_squash(ret));
532 return;
535 /* make_server_info_pw does not set the domain. Without this
536 * we end up with the local netbios name in substitutions for
537 * %D. */
539 if (server_info->info3 != NULL) {
540 server_info->info3->base.domain.string =
541 talloc_strdup(server_info->info3, domain);
545 server_info->nss_token |= username_was_mapped;
547 /* we need to build the token for the user. make_server_info_guest()
548 already does this */
550 if ( !server_info->ptok ) {
551 ret = create_local_token( server_info );
552 if ( !NT_STATUS_IS_OK(ret) ) {
553 DEBUG(10,("failed to create local token: %s\n",
554 nt_errstr(ret)));
555 data_blob_free(&ap_rep);
556 data_blob_free(&session_key);
557 TALLOC_FREE( mem_ctx );
558 TALLOC_FREE( server_info );
559 reply_nterror(req, nt_status_squash(ret));
560 return;
564 if (!is_partial_auth_vuid(sconn, sess_vuid)) {
565 sess_vuid = register_initial_vuid(sconn);
568 data_blob_free(&server_info->user_session_key);
569 server_info->user_session_key = session_key;
570 talloc_steal(server_info, session_key.data);
572 session_key = data_blob_null;
574 /* register_existing_vuid keeps the server info */
575 /* register_existing_vuid takes ownership of session_key on success,
576 * no need to free after this on success. A better interface would copy
577 * it.... */
579 sess_vuid = register_existing_vuid(sconn,
580 sess_vuid,
581 server_info,
582 nullblob,
583 client);
585 reply_outbuf(req, 4, 0);
586 SSVAL(req->outbuf,smb_uid,sess_vuid);
588 if (sess_vuid == UID_FIELD_INVALID ) {
589 ret = NT_STATUS_LOGON_FAILURE;
590 } else {
591 /* current_user_info is changed on new vuid */
592 reload_services(sconn->msg_ctx, sconn->sock, True);
594 SSVAL(req->outbuf, smb_vwv3, 0);
596 if (server_info->guest) {
597 SSVAL(req->outbuf,smb_vwv2,1);
600 SSVAL(req->outbuf, smb_uid, sess_vuid);
602 /* Successful logon. Keep this vuid. */
603 *p_invalidate_vuid = False;
606 /* wrap that up in a nice GSS-API wrapping */
607 if (NT_STATUS_IS_OK(ret)) {
608 ap_rep_wrapped = spnego_gen_krb5_wrap(talloc_tos(), ap_rep,
609 TOK_ID_KRB_AP_REP);
610 } else {
611 ap_rep_wrapped = data_blob_null;
613 response = spnego_gen_auth_response(talloc_tos(), &ap_rep_wrapped, ret,
614 mechOID);
615 reply_sesssetup_blob(req, response, ret);
617 data_blob_free(&ap_rep);
618 data_blob_free(&ap_rep_wrapped);
619 data_blob_free(&response);
620 TALLOC_FREE(mem_ctx);
623 #endif
625 /****************************************************************************
626 Send a session setup reply, wrapped in SPNEGO.
627 Get vuid and check first.
628 End the NTLMSSP exchange context if we are OK/complete fail
629 This should be split into two functions, one to handle each
630 leg of the NTLM auth steps.
631 ***************************************************************************/
633 static void reply_spnego_ntlmssp(struct smb_request *req,
634 uint16 vuid,
635 struct auth_ntlmssp_state **auth_ntlmssp_state,
636 DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status,
637 const char *OID,
638 bool wrap)
640 bool do_invalidate = true;
641 DATA_BLOB response;
642 struct auth_serversupplied_info *server_info = NULL;
643 struct smbd_server_connection *sconn = req->sconn;
645 if (NT_STATUS_IS_OK(nt_status)) {
646 nt_status = auth_ntlmssp_steal_server_info(talloc_tos(),
647 (*auth_ntlmssp_state), &server_info);
648 } else {
649 /* Note that this server_info won't have a session
650 * key. But for map to guest, that's exactly the right
651 * thing - we can't reasonably guess the key the
652 * client wants, as the password was wrong */
653 nt_status = do_map_to_guest(nt_status,
654 &server_info,
655 auth_ntlmssp_get_username(*auth_ntlmssp_state),
656 auth_ntlmssp_get_domain(*auth_ntlmssp_state));
659 reply_outbuf(req, 4, 0);
661 SSVAL(req->outbuf, smb_uid, vuid);
663 if (NT_STATUS_IS_OK(nt_status)) {
664 DATA_BLOB nullblob = data_blob_null;
666 if (!is_partial_auth_vuid(sconn, vuid)) {
667 nt_status = NT_STATUS_LOGON_FAILURE;
668 goto out;
671 /* register_existing_vuid keeps the server info */
672 if (register_existing_vuid(sconn, vuid,
673 server_info, nullblob,
674 auth_ntlmssp_get_username(*auth_ntlmssp_state)) !=
675 vuid) {
676 /* The problem is, *auth_ntlmssp_state points
677 * into the vuser this will have
678 * talloc_free()'ed in
679 * register_existing_vuid() */
680 do_invalidate = false;
681 nt_status = NT_STATUS_LOGON_FAILURE;
682 goto out;
685 /* current_user_info is changed on new vuid */
686 reload_services(sconn->msg_ctx, sconn->sock, True);
688 SSVAL(req->outbuf, smb_vwv3, 0);
690 if (server_info->guest) {
691 SSVAL(req->outbuf,smb_vwv2,1);
695 out:
697 if (wrap) {
698 response = spnego_gen_auth_response(talloc_tos(),
699 ntlmssp_blob,
700 nt_status, OID);
701 } else {
702 response = *ntlmssp_blob;
705 reply_sesssetup_blob(req, response, nt_status);
706 if (wrap) {
707 data_blob_free(&response);
710 /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
711 and the other end, that we are not finished yet. */
713 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
714 /* NB. This is *NOT* an error case. JRA */
715 if (do_invalidate) {
716 TALLOC_FREE(*auth_ntlmssp_state);
717 if (!NT_STATUS_IS_OK(nt_status)) {
718 /* Kill the intermediate vuid */
719 invalidate_vuid(sconn, vuid);
725 /****************************************************************************
726 Is this a krb5 mechanism ?
727 ****************************************************************************/
729 NTSTATUS parse_spnego_mechanisms(TALLOC_CTX *ctx,
730 DATA_BLOB blob_in,
731 DATA_BLOB *pblob_out,
732 char **kerb_mechOID)
734 char *OIDs[ASN1_MAX_OIDS];
735 int i;
736 NTSTATUS ret = NT_STATUS_OK;
738 *kerb_mechOID = NULL;
740 /* parse out the OIDs and the first sec blob */
741 if (!spnego_parse_negTokenInit(ctx, blob_in, OIDs, NULL, pblob_out)) {
742 return NT_STATUS_LOGON_FAILURE;
745 /* only look at the first OID for determining the mechToken --
746 according to RFC2478, we should choose the one we want
747 and renegotiate, but i smell a client bug here..
749 Problem observed when connecting to a member (samba box)
750 of an AD domain as a user in a Samba domain. Samba member
751 server sent back krb5/mskrb5/ntlmssp as mechtypes, but the
752 client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an
753 NTLMSSP mechtoken. --jerry */
755 #ifdef HAVE_KRB5
756 if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||
757 strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
758 *kerb_mechOID = talloc_strdup(ctx, OIDs[0]);
759 if (*kerb_mechOID == NULL) {
760 ret = NT_STATUS_NO_MEMORY;
763 #endif
765 for (i=0;OIDs[i];i++) {
766 DEBUG(5,("parse_spnego_mechanisms: Got OID %s\n", OIDs[i]));
767 talloc_free(OIDs[i]);
769 return ret;
772 /****************************************************************************
773 Fall back from krb5 to NTLMSSP.
774 ****************************************************************************/
776 static void reply_spnego_downgrade_to_ntlmssp(struct smb_request *req,
777 uint16 vuid)
779 DATA_BLOB response;
781 reply_outbuf(req, 4, 0);
782 SSVAL(req->outbuf,smb_uid,vuid);
784 DEBUG(3,("reply_spnego_downgrade_to_ntlmssp: Got krb5 ticket in SPNEGO "
785 "but set to downgrade to NTLMSSP\n"));
787 response = spnego_gen_auth_response(talloc_tos(), NULL,
788 NT_STATUS_MORE_PROCESSING_REQUIRED,
789 OID_NTLMSSP);
790 reply_sesssetup_blob(req, response, NT_STATUS_MORE_PROCESSING_REQUIRED);
791 data_blob_free(&response);
794 /****************************************************************************
795 Reply to a session setup spnego negotiate packet.
796 ****************************************************************************/
798 static void reply_spnego_negotiate(struct smb_request *req,
799 uint16 vuid,
800 DATA_BLOB blob1,
801 struct auth_ntlmssp_state **auth_ntlmssp_state)
803 DATA_BLOB secblob;
804 DATA_BLOB chal;
805 char *kerb_mech = NULL;
806 NTSTATUS status;
807 struct smbd_server_connection *sconn = req->sconn;
809 status = parse_spnego_mechanisms(talloc_tos(),
810 blob1, &secblob, &kerb_mech);
811 if (!NT_STATUS_IS_OK(status)) {
812 /* Kill the intermediate vuid */
813 invalidate_vuid(sconn, vuid);
814 reply_nterror(req, nt_status_squash(status));
815 return;
818 DEBUG(3,("reply_spnego_negotiate: Got secblob of size %lu\n",
819 (unsigned long)secblob.length));
821 #ifdef HAVE_KRB5
822 if (kerb_mech && ((lp_security()==SEC_ADS) ||
823 USE_KERBEROS_KEYTAB) ) {
824 bool destroy_vuid = True;
825 reply_spnego_kerberos(req, &secblob, kerb_mech,
826 vuid, &destroy_vuid);
827 data_blob_free(&secblob);
828 if (destroy_vuid) {
829 /* Kill the intermediate vuid */
830 invalidate_vuid(sconn, vuid);
832 TALLOC_FREE(kerb_mech);
833 return;
835 #endif
837 if (*auth_ntlmssp_state) {
838 TALLOC_FREE(*auth_ntlmssp_state);
841 if (kerb_mech) {
842 data_blob_free(&secblob);
843 /* The mechtoken is a krb5 ticket, but
844 * we need to fall back to NTLM. */
845 reply_spnego_downgrade_to_ntlmssp(req, vuid);
846 TALLOC_FREE(kerb_mech);
847 return;
850 status = auth_ntlmssp_start(auth_ntlmssp_state);
851 if (!NT_STATUS_IS_OK(status)) {
852 /* Kill the intermediate vuid */
853 invalidate_vuid(sconn, vuid);
854 reply_nterror(req, nt_status_squash(status));
855 return;
858 status = auth_ntlmssp_update(*auth_ntlmssp_state,
859 secblob, &chal);
861 data_blob_free(&secblob);
863 reply_spnego_ntlmssp(req, vuid, auth_ntlmssp_state,
864 &chal, status, OID_NTLMSSP, true);
866 data_blob_free(&chal);
868 /* already replied */
869 return;
872 /****************************************************************************
873 Reply to a session setup spnego auth packet.
874 ****************************************************************************/
876 static void reply_spnego_auth(struct smb_request *req,
877 uint16 vuid,
878 DATA_BLOB blob1,
879 struct auth_ntlmssp_state **auth_ntlmssp_state)
881 DATA_BLOB auth = data_blob_null;
882 DATA_BLOB auth_reply = data_blob_null;
883 DATA_BLOB secblob = data_blob_null;
884 NTSTATUS status = NT_STATUS_LOGON_FAILURE;
885 struct smbd_server_connection *sconn = req->sconn;
887 if (!spnego_parse_auth(talloc_tos(), blob1, &auth)) {
888 #if 0
889 file_save("auth.dat", blob1.data, blob1.length);
890 #endif
891 /* Kill the intermediate vuid */
892 invalidate_vuid(sconn, vuid);
894 reply_nterror(req, nt_status_squash(
895 NT_STATUS_LOGON_FAILURE));
896 return;
899 if (auth.data[0] == ASN1_APPLICATION(0)) {
900 /* Might be a second negTokenTarg packet */
901 char *kerb_mech = NULL;
903 status = parse_spnego_mechanisms(talloc_tos(),
904 auth, &secblob, &kerb_mech);
906 if (!NT_STATUS_IS_OK(status)) {
907 /* Kill the intermediate vuid */
908 invalidate_vuid(sconn, vuid);
909 reply_nterror(req, nt_status_squash(status));
910 return;
913 DEBUG(3,("reply_spnego_auth: Got secblob of size %lu\n",
914 (unsigned long)secblob.length));
915 #ifdef HAVE_KRB5
916 if (kerb_mech && ((lp_security()==SEC_ADS) ||
917 USE_KERBEROS_KEYTAB)) {
918 bool destroy_vuid = True;
919 reply_spnego_kerberos(req, &secblob, kerb_mech,
920 vuid, &destroy_vuid);
921 data_blob_free(&secblob);
922 data_blob_free(&auth);
923 if (destroy_vuid) {
924 /* Kill the intermediate vuid */
925 invalidate_vuid(sconn, vuid);
927 TALLOC_FREE(kerb_mech);
928 return;
930 #endif
931 /* Can't blunder into NTLMSSP auth if we have
932 * a krb5 ticket. */
934 if (kerb_mech) {
935 /* Kill the intermediate vuid */
936 invalidate_vuid(sconn, vuid);
937 DEBUG(3,("reply_spnego_auth: network "
938 "misconfiguration, client sent us a "
939 "krb5 ticket and kerberos security "
940 "not enabled\n"));
941 reply_nterror(req, nt_status_squash(
942 NT_STATUS_LOGON_FAILURE));
943 TALLOC_FREE(kerb_mech);
947 /* If we get here it wasn't a negTokenTarg auth packet. */
948 data_blob_free(&secblob);
950 if (!*auth_ntlmssp_state) {
951 status = auth_ntlmssp_start(auth_ntlmssp_state);
952 if (!NT_STATUS_IS_OK(status)) {
953 /* Kill the intermediate vuid */
954 invalidate_vuid(sconn, vuid);
955 reply_nterror(req, nt_status_squash(status));
956 return;
960 status = auth_ntlmssp_update(*auth_ntlmssp_state,
961 auth, &auth_reply);
963 data_blob_free(&auth);
965 /* Don't send the mechid as we've already sent this (RFC4178). */
967 reply_spnego_ntlmssp(req, vuid,
968 auth_ntlmssp_state,
969 &auth_reply, status, NULL, true);
971 data_blob_free(&auth_reply);
973 /* and tell smbd that we have already replied to this packet */
974 return;
977 /****************************************************************************
978 Delete an entry on the list.
979 ****************************************************************************/
981 static void delete_partial_auth(struct smbd_server_connection *sconn,
982 struct pending_auth_data *pad)
984 if (!pad) {
985 return;
987 DLIST_REMOVE(sconn->smb1.pd_list, pad);
988 data_blob_free(&pad->partial_data);
989 SAFE_FREE(pad);
992 /****************************************************************************
993 Search for a partial SPNEGO auth fragment matching an smbpid.
994 ****************************************************************************/
996 static struct pending_auth_data *get_pending_auth_data(
997 struct smbd_server_connection *sconn,
998 uint16_t smbpid)
1000 struct pending_auth_data *pad;
1002 * NOTE: using the smbpid here is completely wrong...
1003 * see [MS-SMB]
1004 * 3.3.5.3 Receiving an SMB_COM_SESSION_SETUP_ANDX Request
1006 for (pad = sconn->smb1.pd_list; pad; pad = pad->next) {
1007 if (pad->smbpid == smbpid) {
1008 break;
1011 return pad;
1014 /****************************************************************************
1015 Check the size of an SPNEGO blob. If we need more return
1016 NT_STATUS_MORE_PROCESSING_REQUIRED, else return NT_STATUS_OK. Don't allow
1017 the blob to be more than 64k.
1018 ****************************************************************************/
1020 static NTSTATUS check_spnego_blob_complete(struct smbd_server_connection *sconn,
1021 uint16 smbpid, uint16 vuid,
1022 DATA_BLOB *pblob)
1024 struct pending_auth_data *pad = NULL;
1025 ASN1_DATA *data;
1026 size_t needed_len = 0;
1028 pad = get_pending_auth_data(sconn, smbpid);
1030 /* Ensure we have some data. */
1031 if (pblob->length == 0) {
1032 /* Caller can cope. */
1033 DEBUG(2,("check_spnego_blob_complete: zero blob length !\n"));
1034 delete_partial_auth(sconn, pad);
1035 return NT_STATUS_OK;
1038 /* Were we waiting for more data ? */
1039 if (pad) {
1040 DATA_BLOB tmp_blob;
1041 size_t copy_len = MIN(65536, pblob->length);
1043 /* Integer wrap paranoia.... */
1045 if (pad->partial_data.length + copy_len <
1046 pad->partial_data.length ||
1047 pad->partial_data.length + copy_len < copy_len) {
1049 DEBUG(2,("check_spnego_blob_complete: integer wrap "
1050 "pad->partial_data.length = %u, "
1051 "copy_len = %u\n",
1052 (unsigned int)pad->partial_data.length,
1053 (unsigned int)copy_len ));
1055 delete_partial_auth(sconn, pad);
1056 return NT_STATUS_INVALID_PARAMETER;
1059 DEBUG(10,("check_spnego_blob_complete: "
1060 "pad->partial_data.length = %u, "
1061 "pad->needed_len = %u, "
1062 "copy_len = %u, "
1063 "pblob->length = %u,\n",
1064 (unsigned int)pad->partial_data.length,
1065 (unsigned int)pad->needed_len,
1066 (unsigned int)copy_len,
1067 (unsigned int)pblob->length ));
1069 tmp_blob = data_blob(NULL,
1070 pad->partial_data.length + copy_len);
1072 /* Concatenate the two (up to copy_len) bytes. */
1073 memcpy(tmp_blob.data,
1074 pad->partial_data.data,
1075 pad->partial_data.length);
1076 memcpy(tmp_blob.data + pad->partial_data.length,
1077 pblob->data,
1078 copy_len);
1080 /* Replace the partial data. */
1081 data_blob_free(&pad->partial_data);
1082 pad->partial_data = tmp_blob;
1083 ZERO_STRUCT(tmp_blob);
1085 /* Are we done ? */
1086 if (pblob->length >= pad->needed_len) {
1087 /* Yes, replace pblob. */
1088 data_blob_free(pblob);
1089 *pblob = pad->partial_data;
1090 ZERO_STRUCT(pad->partial_data);
1091 delete_partial_auth(sconn, pad);
1092 return NT_STATUS_OK;
1095 /* Still need more data. */
1096 pad->needed_len -= copy_len;
1097 return NT_STATUS_MORE_PROCESSING_REQUIRED;
1100 if ((pblob->data[0] != ASN1_APPLICATION(0)) &&
1101 (pblob->data[0] != ASN1_CONTEXT(1))) {
1102 /* Not something we can determine the
1103 * length of.
1105 return NT_STATUS_OK;
1108 /* This is a new SPNEGO sessionsetup - see if
1109 * the data given in this blob is enough.
1112 data = asn1_init(NULL);
1113 if (data == NULL) {
1114 return NT_STATUS_NO_MEMORY;
1117 asn1_load(data, *pblob);
1118 asn1_start_tag(data, pblob->data[0]);
1119 if (data->has_error || data->nesting == NULL) {
1120 asn1_free(data);
1121 /* Let caller catch. */
1122 return NT_STATUS_OK;
1125 /* Integer wrap paranoia.... */
1127 if (data->nesting->taglen + data->nesting->start < data->nesting->taglen ||
1128 data->nesting->taglen + data->nesting->start < data->nesting->start) {
1130 DEBUG(2,("check_spnego_blob_complete: integer wrap "
1131 "data.nesting->taglen = %u, "
1132 "data.nesting->start = %u\n",
1133 (unsigned int)data->nesting->taglen,
1134 (unsigned int)data->nesting->start ));
1136 asn1_free(data);
1137 return NT_STATUS_INVALID_PARAMETER;
1140 /* Total length of the needed asn1 is the tag length
1141 * plus the current offset. */
1143 needed_len = data->nesting->taglen + data->nesting->start;
1144 asn1_free(data);
1146 DEBUG(10,("check_spnego_blob_complete: needed_len = %u, "
1147 "pblob->length = %u\n",
1148 (unsigned int)needed_len,
1149 (unsigned int)pblob->length ));
1151 if (needed_len <= pblob->length) {
1152 /* Nothing to do - blob is complete. */
1153 return NT_STATUS_OK;
1156 /* Refuse the blob if it's bigger than 64k. */
1157 if (needed_len > 65536) {
1158 DEBUG(2,("check_spnego_blob_complete: needed_len "
1159 "too large (%u)\n",
1160 (unsigned int)needed_len ));
1161 return NT_STATUS_INVALID_PARAMETER;
1164 /* We must store this blob until complete. */
1165 if (!(pad = SMB_MALLOC_P(struct pending_auth_data))) {
1166 return NT_STATUS_NO_MEMORY;
1168 pad->needed_len = needed_len - pblob->length;
1169 pad->partial_data = data_blob(pblob->data, pblob->length);
1170 if (pad->partial_data.data == NULL) {
1171 SAFE_FREE(pad);
1172 return NT_STATUS_NO_MEMORY;
1174 pad->smbpid = smbpid;
1175 pad->vuid = vuid;
1176 DLIST_ADD(sconn->smb1.pd_list, pad);
1178 return NT_STATUS_MORE_PROCESSING_REQUIRED;
1181 /****************************************************************************
1182 Reply to a session setup command.
1183 conn POINTER CAN BE NULL HERE !
1184 ****************************************************************************/
1186 static void reply_sesssetup_and_X_spnego(struct smb_request *req)
1188 const uint8 *p;
1189 DATA_BLOB blob1;
1190 size_t bufrem;
1191 char *tmp;
1192 const char *native_os;
1193 const char *native_lanman;
1194 const char *primary_domain;
1195 const char *p2;
1196 uint16 data_blob_len = SVAL(req->vwv+7, 0);
1197 enum remote_arch_types ra_type = get_remote_arch();
1198 int vuid = req->vuid;
1199 user_struct *vuser = NULL;
1200 NTSTATUS status = NT_STATUS_OK;
1201 uint16 smbpid = req->smbpid;
1202 struct smbd_server_connection *sconn = req->sconn;
1204 DEBUG(3,("Doing spnego session setup\n"));
1206 if (global_client_caps == 0) {
1207 global_client_caps = IVAL(req->vwv+10, 0);
1209 if (!(global_client_caps & CAP_STATUS32)) {
1210 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1215 p = req->buf;
1217 if (data_blob_len == 0) {
1218 /* an invalid request */
1219 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1220 return;
1223 bufrem = smbreq_bufrem(req, p);
1224 /* pull the spnego blob */
1225 blob1 = data_blob(p, MIN(bufrem, data_blob_len));
1227 #if 0
1228 file_save("negotiate.dat", blob1.data, blob1.length);
1229 #endif
1231 p2 = (char *)req->buf + blob1.length;
1233 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1234 STR_TERMINATE);
1235 native_os = tmp ? tmp : "";
1237 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1238 STR_TERMINATE);
1239 native_lanman = tmp ? tmp : "";
1241 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1242 STR_TERMINATE);
1243 primary_domain = tmp ? tmp : "";
1245 DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
1246 native_os, native_lanman, primary_domain));
1248 if ( ra_type == RA_WIN2K ) {
1249 /* Vista sets neither the OS or lanman strings */
1251 if ( !strlen(native_os) && !strlen(native_lanman) )
1252 set_remote_arch(RA_VISTA);
1254 /* Windows 2003 doesn't set the native lanman string,
1255 but does set primary domain which is a bug I think */
1257 if ( !strlen(native_lanman) ) {
1258 ra_lanman_string( primary_domain );
1259 } else {
1260 ra_lanman_string( native_lanman );
1264 /* Did we get a valid vuid ? */
1265 if (!is_partial_auth_vuid(sconn, vuid)) {
1266 /* No, then try and see if this is an intermediate sessionsetup
1267 * for a large SPNEGO packet. */
1268 struct pending_auth_data *pad;
1269 pad = get_pending_auth_data(sconn, smbpid);
1270 if (pad) {
1271 DEBUG(10,("reply_sesssetup_and_X_spnego: found "
1272 "pending vuid %u\n",
1273 (unsigned int)pad->vuid ));
1274 vuid = pad->vuid;
1278 /* Do we have a valid vuid now ? */
1279 if (!is_partial_auth_vuid(sconn, vuid)) {
1280 /* No, start a new authentication setup. */
1281 vuid = register_initial_vuid(sconn);
1282 if (vuid == UID_FIELD_INVALID) {
1283 data_blob_free(&blob1);
1284 reply_nterror(req, nt_status_squash(
1285 NT_STATUS_INVALID_PARAMETER));
1286 return;
1290 vuser = get_partial_auth_user_struct(sconn, vuid);
1291 /* This MUST be valid. */
1292 if (!vuser) {
1293 smb_panic("reply_sesssetup_and_X_spnego: invalid vuid.");
1296 /* Large (greater than 4k) SPNEGO blobs are split into multiple
1297 * sessionsetup requests as the Windows limit on the security blob
1298 * field is 4k. Bug #4400. JRA.
1301 status = check_spnego_blob_complete(sconn, smbpid, vuid, &blob1);
1302 if (!NT_STATUS_IS_OK(status)) {
1303 if (!NT_STATUS_EQUAL(status,
1304 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1305 /* Real error - kill the intermediate vuid */
1306 invalidate_vuid(sconn, vuid);
1308 data_blob_free(&blob1);
1309 reply_nterror(req, nt_status_squash(status));
1310 return;
1313 if (blob1.data[0] == ASN1_APPLICATION(0)) {
1315 /* its a negTokenTarg packet */
1317 reply_spnego_negotiate(req, vuid, blob1,
1318 &vuser->auth_ntlmssp_state);
1319 data_blob_free(&blob1);
1320 return;
1323 if (blob1.data[0] == ASN1_CONTEXT(1)) {
1325 /* its a auth packet */
1327 reply_spnego_auth(req, vuid, blob1,
1328 &vuser->auth_ntlmssp_state);
1329 data_blob_free(&blob1);
1330 return;
1333 if (strncmp((char *)(blob1.data), "NTLMSSP", 7) == 0) {
1334 DATA_BLOB chal;
1336 if (!vuser->auth_ntlmssp_state) {
1337 status = auth_ntlmssp_start(&vuser->auth_ntlmssp_state);
1338 if (!NT_STATUS_IS_OK(status)) {
1339 /* Kill the intermediate vuid */
1340 invalidate_vuid(sconn, vuid);
1341 data_blob_free(&blob1);
1342 reply_nterror(req, nt_status_squash(status));
1343 return;
1347 status = auth_ntlmssp_update(vuser->auth_ntlmssp_state,
1348 blob1, &chal);
1350 data_blob_free(&blob1);
1352 reply_spnego_ntlmssp(req, vuid,
1353 &vuser->auth_ntlmssp_state,
1354 &chal, status, OID_NTLMSSP, false);
1355 data_blob_free(&chal);
1356 return;
1359 /* what sort of packet is this? */
1360 DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
1362 data_blob_free(&blob1);
1364 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1367 /****************************************************************************
1368 On new VC == 0, shutdown *all* old connections and users.
1369 It seems that only NT4.x does this. At W2K and above (XP etc.).
1370 a new session setup with VC==0 is ignored.
1371 ****************************************************************************/
1373 struct shutdown_state {
1374 const char *ip;
1375 struct messaging_context *msg_ctx;
1378 static int shutdown_other_smbds(const struct connections_key *key,
1379 const struct connections_data *crec,
1380 void *private_data)
1382 struct shutdown_state *state = (struct shutdown_state *)private_data;
1384 DEBUG(10, ("shutdown_other_smbds: %s, %s\n",
1385 procid_str(talloc_tos(), &crec->pid), crec->addr));
1387 if (!process_exists(crec->pid)) {
1388 DEBUG(10, ("process does not exist\n"));
1389 return 0;
1392 if (procid_is_me(&crec->pid)) {
1393 DEBUG(10, ("It's me\n"));
1394 return 0;
1397 if (strcmp(state->ip, crec->addr) != 0) {
1398 DEBUG(10, ("%s does not match %s\n", state->ip, crec->addr));
1399 return 0;
1402 DEBUG(1, ("shutdown_other_smbds: shutting down pid %u "
1403 "(IP %s)\n", (unsigned int)procid_to_pid(&crec->pid),
1404 state->ip));
1406 messaging_send(state->msg_ctx, crec->pid, MSG_SHUTDOWN,
1407 &data_blob_null);
1408 return 0;
1411 static void setup_new_vc_session(struct smbd_server_connection *sconn)
1413 DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x "
1414 "compatible we would close all old resources.\n"));
1415 #if 0
1416 conn_close_all();
1417 invalidate_all_vuids();
1418 #endif
1419 if (lp_reset_on_zero_vc()) {
1420 char *addr;
1421 struct shutdown_state state;
1423 addr = tsocket_address_inet_addr_string(
1424 sconn->remote_address, talloc_tos());
1425 if (addr == NULL) {
1426 return;
1428 state.ip = addr;
1429 state.msg_ctx = sconn->msg_ctx;
1430 connections_forall_read(shutdown_other_smbds, &state);
1431 TALLOC_FREE(addr);
1435 /****************************************************************************
1436 Reply to a session setup command.
1437 ****************************************************************************/
1439 void reply_sesssetup_and_X(struct smb_request *req)
1441 int sess_vuid;
1442 int smb_bufsize;
1443 DATA_BLOB lm_resp;
1444 DATA_BLOB nt_resp;
1445 DATA_BLOB plaintext_password;
1446 char *tmp;
1447 const char *user;
1448 fstring sub_user; /* Sanitised username for substituion */
1449 const char *domain;
1450 const char *native_os;
1451 const char *native_lanman;
1452 const char *primary_domain;
1453 struct auth_usersupplied_info *user_info = NULL;
1454 struct auth_serversupplied_info *server_info = NULL;
1455 uint16 smb_flag2 = req->flags2;
1457 NTSTATUS nt_status;
1458 struct smbd_server_connection *sconn = req->sconn;
1460 bool doencrypt = sconn->smb1.negprot.encrypted_passwords;
1462 START_PROFILE(SMBsesssetupX);
1464 ZERO_STRUCT(lm_resp);
1465 ZERO_STRUCT(nt_resp);
1466 ZERO_STRUCT(plaintext_password);
1468 DEBUG(3,("wct=%d flg2=0x%x\n", req->wct, req->flags2));
1470 /* a SPNEGO session setup has 12 command words, whereas a normal
1471 NT1 session setup has 13. See the cifs spec. */
1472 if (req->wct == 12 &&
1473 (req->flags2 & FLAGS2_EXTENDED_SECURITY)) {
1475 if (!sconn->smb1.negprot.spnego) {
1476 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt "
1477 "at SPNEGO session setup when it was not "
1478 "negotiated.\n"));
1479 reply_nterror(req, nt_status_squash(
1480 NT_STATUS_LOGON_FAILURE));
1481 END_PROFILE(SMBsesssetupX);
1482 return;
1485 if (SVAL(req->vwv+4, 0) == 0) {
1486 setup_new_vc_session(req->sconn);
1489 reply_sesssetup_and_X_spnego(req);
1490 END_PROFILE(SMBsesssetupX);
1491 return;
1494 smb_bufsize = SVAL(req->vwv+2, 0);
1496 if (get_Protocol() < PROTOCOL_NT1) {
1497 uint16 passlen1 = SVAL(req->vwv+7, 0);
1499 /* Never do NT status codes with protocols before NT1 as we
1500 * don't get client caps. */
1501 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1503 if ((passlen1 > MAX_PASS_LEN) || (passlen1 > req->buflen)) {
1504 reply_nterror(req, nt_status_squash(
1505 NT_STATUS_INVALID_PARAMETER));
1506 END_PROFILE(SMBsesssetupX);
1507 return;
1510 if (doencrypt) {
1511 lm_resp = data_blob(req->buf, passlen1);
1512 } else {
1513 plaintext_password = data_blob(req->buf, passlen1+1);
1514 /* Ensure null termination */
1515 plaintext_password.data[passlen1] = 0;
1518 srvstr_pull_req_talloc(talloc_tos(), req, &tmp,
1519 req->buf + passlen1, STR_TERMINATE);
1520 user = tmp ? tmp : "";
1522 domain = "";
1524 } else {
1525 uint16 passlen1 = SVAL(req->vwv+7, 0);
1526 uint16 passlen2 = SVAL(req->vwv+8, 0);
1527 enum remote_arch_types ra_type = get_remote_arch();
1528 const uint8_t *p = req->buf;
1529 const uint8_t *save_p = req->buf;
1530 uint16 byte_count;
1533 if(global_client_caps == 0) {
1534 global_client_caps = IVAL(req->vwv+11, 0);
1536 if (!(global_client_caps & CAP_STATUS32)) {
1537 remove_from_common_flags2(
1538 FLAGS2_32_BIT_ERROR_CODES);
1541 /* client_caps is used as final determination if
1542 * client is NT or Win95. This is needed to return
1543 * the correct error codes in some circumstances.
1546 if(ra_type == RA_WINNT || ra_type == RA_WIN2K ||
1547 ra_type == RA_WIN95) {
1548 if(!(global_client_caps & (CAP_NT_SMBS|
1549 CAP_STATUS32))) {
1550 set_remote_arch( RA_WIN95);
1555 if (!doencrypt) {
1556 /* both Win95 and WinNT stuff up the password
1557 * lengths for non-encrypting systems. Uggh.
1559 if passlen1==24 its a win95 system, and its setting
1560 the password length incorrectly. Luckily it still
1561 works with the default code because Win95 will null
1562 terminate the password anyway
1564 if passlen1>0 and passlen2>0 then maybe its a NT box
1565 and its setting passlen2 to some random value which
1566 really stuffs things up. we need to fix that one. */
1568 if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 &&
1569 passlen2 != 1) {
1570 passlen2 = 0;
1574 /* check for nasty tricks */
1575 if (passlen1 > MAX_PASS_LEN
1576 || passlen1 > smbreq_bufrem(req, p)) {
1577 reply_nterror(req, nt_status_squash(
1578 NT_STATUS_INVALID_PARAMETER));
1579 END_PROFILE(SMBsesssetupX);
1580 return;
1583 if (passlen2 > MAX_PASS_LEN
1584 || passlen2 > smbreq_bufrem(req, p+passlen1)) {
1585 reply_nterror(req, nt_status_squash(
1586 NT_STATUS_INVALID_PARAMETER));
1587 END_PROFILE(SMBsesssetupX);
1588 return;
1591 /* Save the lanman2 password and the NT md4 password. */
1593 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
1594 doencrypt = False;
1597 if (doencrypt) {
1598 lm_resp = data_blob(p, passlen1);
1599 nt_resp = data_blob(p+passlen1, passlen2);
1600 } else if (lp_security() != SEC_SHARE) {
1602 * In share level we should ignore any passwords, so
1603 * only read them if we're not.
1605 char *pass = NULL;
1606 bool unic= smb_flag2 & FLAGS2_UNICODE_STRINGS;
1608 if (unic && (passlen2 == 0) && passlen1) {
1609 /* Only a ascii plaintext password was sent. */
1610 (void)srvstr_pull_talloc(talloc_tos(),
1611 req->inbuf,
1612 req->flags2,
1613 &pass,
1614 req->buf,
1615 passlen1,
1616 STR_TERMINATE|STR_ASCII);
1617 } else {
1618 (void)srvstr_pull_talloc(talloc_tos(),
1619 req->inbuf,
1620 req->flags2,
1621 &pass,
1622 req->buf,
1623 unic ? passlen2 : passlen1,
1624 STR_TERMINATE);
1626 if (!pass) {
1627 reply_nterror(req, nt_status_squash(
1628 NT_STATUS_INVALID_PARAMETER));
1629 END_PROFILE(SMBsesssetupX);
1630 return;
1632 plaintext_password = data_blob(pass, strlen(pass)+1);
1635 p += passlen1 + passlen2;
1637 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1638 STR_TERMINATE);
1639 user = tmp ? tmp : "";
1641 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1642 STR_TERMINATE);
1643 domain = tmp ? tmp : "";
1645 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1646 STR_TERMINATE);
1647 native_os = tmp ? tmp : "";
1649 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1650 STR_TERMINATE);
1651 native_lanman = tmp ? tmp : "";
1653 /* not documented or decoded by Ethereal but there is one more
1654 * string in the extra bytes which is the same as the
1655 * PrimaryDomain when using extended security. Windows NT 4
1656 * and 2003 use this string to store the native lanman string.
1657 * Windows 9x does not include a string here at all so we have
1658 * to check if we have any extra bytes left */
1660 byte_count = SVAL(req->vwv+13, 0);
1661 if ( PTR_DIFF(p, save_p) < byte_count) {
1662 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1663 STR_TERMINATE);
1664 primary_domain = tmp ? tmp : "";
1665 } else {
1666 primary_domain = talloc_strdup(talloc_tos(), "null");
1669 DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s] "
1670 "PrimaryDomain=[%s]\n",
1671 domain, native_os, native_lanman, primary_domain));
1673 if ( ra_type == RA_WIN2K ) {
1674 if ( strlen(native_lanman) == 0 )
1675 ra_lanman_string( primary_domain );
1676 else
1677 ra_lanman_string( native_lanman );
1682 if (SVAL(req->vwv+4, 0) == 0) {
1683 setup_new_vc_session(req->sconn);
1686 DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n",
1687 domain, user, get_remote_machine_name()));
1689 if (*user) {
1690 if (sconn->smb1.negprot.spnego) {
1692 /* This has to be here, because this is a perfectly
1693 * valid behaviour for guest logons :-( */
1695 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt "
1696 "at 'normal' session setup after "
1697 "negotiating spnego.\n"));
1698 reply_nterror(req, nt_status_squash(
1699 NT_STATUS_LOGON_FAILURE));
1700 END_PROFILE(SMBsesssetupX);
1701 return;
1703 fstrcpy(sub_user, user);
1704 } else {
1705 fstrcpy(sub_user, lp_guestaccount());
1708 sub_set_smb_name(sub_user);
1710 reload_services(sconn->msg_ctx, sconn->sock, True);
1712 if (lp_security() == SEC_SHARE) {
1713 /* In share level we should ignore any passwords */
1715 data_blob_free(&lm_resp);
1716 data_blob_free(&nt_resp);
1717 data_blob_clear_free(&plaintext_password);
1719 map_username(sub_user);
1720 add_session_user(sconn, sub_user);
1721 add_session_workgroup(sconn, domain);
1722 /* Then force it to null for the benfit of the code below */
1723 user = "";
1726 if (!*user) {
1728 nt_status = check_guest_password(&server_info);
1730 } else if (doencrypt) {
1731 struct auth_context *negprot_auth_context = NULL;
1732 negprot_auth_context = sconn->smb1.negprot.auth_context;
1733 if (!negprot_auth_context) {
1734 DEBUG(0, ("reply_sesssetup_and_X: Attempted encrypted "
1735 "session setup without negprot denied!\n"));
1736 reply_nterror(req, nt_status_squash(
1737 NT_STATUS_LOGON_FAILURE));
1738 END_PROFILE(SMBsesssetupX);
1739 return;
1741 nt_status = make_user_info_for_reply_enc(&user_info, user,
1742 domain,
1743 lm_resp, nt_resp);
1744 if (NT_STATUS_IS_OK(nt_status)) {
1745 nt_status = negprot_auth_context->check_ntlm_password(
1746 negprot_auth_context,
1747 user_info,
1748 &server_info);
1750 } else {
1751 struct auth_context *plaintext_auth_context = NULL;
1753 nt_status = make_auth_context_subsystem(
1754 &plaintext_auth_context);
1756 if (NT_STATUS_IS_OK(nt_status)) {
1757 uint8_t chal[8];
1759 plaintext_auth_context->get_ntlm_challenge(
1760 plaintext_auth_context, chal);
1762 if (!make_user_info_for_reply(&user_info,
1763 user, domain, chal,
1764 plaintext_password)) {
1765 nt_status = NT_STATUS_NO_MEMORY;
1768 if (NT_STATUS_IS_OK(nt_status)) {
1769 nt_status = plaintext_auth_context->check_ntlm_password(
1770 plaintext_auth_context,
1771 user_info,
1772 &server_info);
1774 TALLOC_FREE(plaintext_auth_context);
1779 free_user_info(&user_info);
1781 if (!NT_STATUS_IS_OK(nt_status)) {
1782 nt_status = do_map_to_guest(nt_status, &server_info,
1783 user, domain);
1786 if (!NT_STATUS_IS_OK(nt_status)) {
1787 data_blob_free(&nt_resp);
1788 data_blob_free(&lm_resp);
1789 data_blob_clear_free(&plaintext_password);
1790 reply_nterror(req, nt_status_squash(nt_status));
1791 END_PROFILE(SMBsesssetupX);
1792 return;
1795 /* Ensure we can't possible take a code path leading to a
1796 * null defref. */
1797 if (!server_info) {
1798 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1799 END_PROFILE(SMBsesssetupX);
1800 return;
1803 if (!server_info->ptok) {
1804 nt_status = create_local_token(server_info);
1806 if (!NT_STATUS_IS_OK(nt_status)) {
1807 DEBUG(10, ("create_local_token failed: %s\n",
1808 nt_errstr(nt_status)));
1809 data_blob_free(&nt_resp);
1810 data_blob_free(&lm_resp);
1811 data_blob_clear_free(&plaintext_password);
1812 reply_nterror(req, nt_status_squash(nt_status));
1813 END_PROFILE(SMBsesssetupX);
1814 return;
1818 data_blob_clear_free(&plaintext_password);
1820 /* it's ok - setup a reply */
1821 reply_outbuf(req, 3, 0);
1822 if (get_Protocol() >= PROTOCOL_NT1) {
1823 push_signature(&req->outbuf);
1824 /* perhaps grab OS version here?? */
1827 if (server_info->guest) {
1828 SSVAL(req->outbuf,smb_vwv2,1);
1831 /* register the name and uid as being validated, so further connections
1832 to a uid can get through without a password, on the same VC */
1834 if (lp_security() == SEC_SHARE) {
1835 sess_vuid = UID_FIELD_INVALID;
1836 TALLOC_FREE(server_info);
1837 } else {
1838 /* Ignore the initial vuid. */
1839 sess_vuid = register_initial_vuid(sconn);
1840 if (sess_vuid == UID_FIELD_INVALID) {
1841 data_blob_free(&nt_resp);
1842 data_blob_free(&lm_resp);
1843 reply_nterror(req, nt_status_squash(
1844 NT_STATUS_LOGON_FAILURE));
1845 END_PROFILE(SMBsesssetupX);
1846 return;
1848 /* register_existing_vuid keeps the server info */
1849 sess_vuid = register_existing_vuid(sconn, sess_vuid,
1850 server_info,
1851 nt_resp.data ? nt_resp : lm_resp,
1852 sub_user);
1853 if (sess_vuid == UID_FIELD_INVALID) {
1854 data_blob_free(&nt_resp);
1855 data_blob_free(&lm_resp);
1856 reply_nterror(req, nt_status_squash(
1857 NT_STATUS_LOGON_FAILURE));
1858 END_PROFILE(SMBsesssetupX);
1859 return;
1862 /* current_user_info is changed on new vuid */
1863 reload_services(sconn->msg_ctx, sconn->sock, True);
1866 data_blob_free(&nt_resp);
1867 data_blob_free(&lm_resp);
1869 SSVAL(req->outbuf,smb_uid,sess_vuid);
1870 SSVAL(req->inbuf,smb_uid,sess_vuid);
1871 req->vuid = sess_vuid;
1873 if (!sconn->smb1.sessions.done_sesssetup) {
1874 sconn->smb1.sessions.max_send =
1875 MIN(sconn->smb1.sessions.max_send,smb_bufsize);
1877 sconn->smb1.sessions.done_sesssetup = true;
1879 END_PROFILE(SMBsesssetupX);
1880 chain_reply(req);
1881 return;