s3/swat: use strlcat instead of strncat to fix build on old Linux distros
[Samba.git] / source3 / smbd / sesssetup.c
blob2a30a789f4046936e4b63b498d8291ba3b9df29d
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"
28 extern enum protocol_types Protocol;
31 on a logon error possibly map the error to success if "map to guest"
32 is set approriately
34 static NTSTATUS do_map_to_guest(NTSTATUS status,
35 auth_serversupplied_info **server_info,
36 const char *user, const char *domain)
38 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
39 if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) ||
40 (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) {
41 DEBUG(3,("No such user %s [%s] - using guest account\n",
42 user, domain));
43 status = make_server_info_guest(NULL, server_info);
47 if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
48 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) {
49 DEBUG(3,("Registered username %s for guest access\n",
50 user));
51 status = make_server_info_guest(NULL, server_info);
55 return status;
58 /****************************************************************************
59 Add the standard 'Samba' signature to the end of the session setup.
60 ****************************************************************************/
62 static int push_signature(uint8 **outbuf)
64 char *lanman;
65 int result, tmp;
67 result = 0;
69 tmp = message_push_string(outbuf, "Unix", STR_TERMINATE);
71 if (tmp == -1) return -1;
72 result += tmp;
74 if (asprintf(&lanman, "Samba %s", samba_version_string()) != -1) {
75 tmp = message_push_string(outbuf, lanman, STR_TERMINATE);
76 SAFE_FREE(lanman);
78 else {
79 tmp = message_push_string(outbuf, "Samba", STR_TERMINATE);
82 if (tmp == -1) return -1;
83 result += tmp;
85 tmp = message_push_string(outbuf, lp_workgroup(), STR_TERMINATE);
87 if (tmp == -1) return -1;
88 result += tmp;
90 return result;
93 /****************************************************************************
94 Start the signing engine if needed. Don't fail signing here.
95 ****************************************************************************/
97 static void sessionsetup_start_signing_engine(
98 const auth_serversupplied_info *server_info,
99 const uint8 *inbuf)
101 if (!server_info->guest && !srv_signing_started()) {
102 /* We need to start the signing engine
103 * here but a W2K client sends the old
104 * "BSRSPYL " signature instead of the
105 * correct one. Subsequent packets will
106 * be correct.
108 srv_check_sign_mac((char *)inbuf, False);
112 /****************************************************************************
113 Send a security blob via a session setup reply.
114 ****************************************************************************/
116 static void reply_sesssetup_blob(struct smb_request *req,
117 DATA_BLOB blob,
118 NTSTATUS nt_status)
120 if (!NT_STATUS_IS_OK(nt_status) &&
121 !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
122 reply_nterror(req, nt_status_squash(nt_status));
123 return;
126 nt_status = nt_status_squash(nt_status);
127 SIVAL(req->outbuf, smb_rcls, NT_STATUS_V(nt_status));
128 SSVAL(req->outbuf, smb_vwv0, 0xFF); /* no chaining possible */
129 SSVAL(req->outbuf, smb_vwv3, blob.length);
131 if ((message_push_blob(&req->outbuf, blob) == -1)
132 || (push_signature(&req->outbuf) == -1)) {
133 reply_nterror(req, NT_STATUS_NO_MEMORY);
137 /****************************************************************************
138 Do a 'guest' logon, getting back the
139 ****************************************************************************/
141 static NTSTATUS check_guest_password(auth_serversupplied_info **server_info)
143 struct auth_context *auth_context;
144 auth_usersupplied_info *user_info = NULL;
146 NTSTATUS nt_status;
147 unsigned char chal[8];
149 ZERO_STRUCT(chal);
151 DEBUG(3,("Got anonymous request\n"));
153 if (!NT_STATUS_IS_OK(nt_status = make_auth_context_fixed(&auth_context,
154 chal))) {
155 return nt_status;
158 if (!make_user_info_guest(&user_info)) {
159 (auth_context->free)(&auth_context);
160 return NT_STATUS_NO_MEMORY;
163 nt_status = auth_context->check_ntlm_password(auth_context,
164 user_info,
165 server_info);
166 (auth_context->free)(&auth_context);
167 free_user_info(&user_info);
168 return nt_status;
172 #ifdef HAVE_KRB5
174 #if 0
175 /* Experiment that failed. See "only happens with a KDC" comment below. */
176 /****************************************************************************
177 Cerate a clock skew error blob for a Windows client.
178 ****************************************************************************/
180 static bool make_krb5_skew_error(DATA_BLOB *pblob_out)
182 krb5_context context = NULL;
183 krb5_error_code kerr = 0;
184 krb5_data reply;
185 krb5_principal host_princ = NULL;
186 char *host_princ_s = NULL;
187 bool ret = False;
189 *pblob_out = data_blob_null;
191 initialize_krb5_error_table();
192 kerr = krb5_init_context(&context);
193 if (kerr) {
194 return False;
196 /* Create server principal. */
197 asprintf(&host_princ_s, "%s$@%s", global_myname(), lp_realm());
198 if (!host_princ_s) {
199 goto out;
201 strlower_m(host_princ_s);
203 kerr = smb_krb5_parse_name(context, host_princ_s, &host_princ);
204 if (kerr) {
205 DEBUG(10,("make_krb5_skew_error: smb_krb5_parse_name failed "
206 "for name %s: Error %s\n",
207 host_princ_s, error_message(kerr) ));
208 goto out;
211 kerr = smb_krb5_mk_error(context, KRB5KRB_AP_ERR_SKEW,
212 host_princ, &reply);
213 if (kerr) {
214 DEBUG(10,("make_krb5_skew_error: smb_krb5_mk_error "
215 "failed: Error %s\n",
216 error_message(kerr) ));
217 goto out;
220 *pblob_out = data_blob(reply.data, reply.length);
221 kerberos_free_data_contents(context,&reply);
222 ret = True;
224 out:
226 if (host_princ_s) {
227 SAFE_FREE(host_princ_s);
229 if (host_princ) {
230 krb5_free_principal(context, host_princ);
232 krb5_free_context(context);
233 return ret;
235 #endif
237 /****************************************************************************
238 Reply to a session setup spnego negotiate packet for kerberos.
239 ****************************************************************************/
241 static void reply_spnego_kerberos(struct smb_request *req,
242 DATA_BLOB *secblob,
243 const char *mechOID,
244 uint16 vuid,
245 bool *p_invalidate_vuid)
247 TALLOC_CTX *mem_ctx;
248 DATA_BLOB ticket;
249 char *client, *p, *domain;
250 fstring netbios_domain_name;
251 struct passwd *pw;
252 fstring user;
253 int sess_vuid = req->vuid;
254 NTSTATUS ret = NT_STATUS_OK;
255 struct PAC_DATA *pac_data = NULL;
256 DATA_BLOB ap_rep, ap_rep_wrapped, response;
257 auth_serversupplied_info *server_info = NULL;
258 DATA_BLOB session_key = data_blob_null;
259 uint8 tok_id[2];
260 DATA_BLOB nullblob = data_blob_null;
261 fstring real_username;
262 bool map_domainuser_to_guest = False;
263 bool username_was_mapped;
264 struct PAC_LOGON_INFO *logon_info = NULL;
266 ZERO_STRUCT(ticket);
267 ZERO_STRUCT(ap_rep);
268 ZERO_STRUCT(ap_rep_wrapped);
269 ZERO_STRUCT(response);
271 /* Normally we will always invalidate the intermediate vuid. */
272 *p_invalidate_vuid = True;
274 mem_ctx = talloc_init("reply_spnego_kerberos");
275 if (mem_ctx == NULL) {
276 reply_nterror(req, nt_status_squash(NT_STATUS_NO_MEMORY));
277 return;
280 if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) {
281 talloc_destroy(mem_ctx);
282 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
283 return;
286 ret = ads_verify_ticket(mem_ctx, lp_realm(), 0, &ticket,
287 &client, &pac_data, &ap_rep,
288 &session_key, True);
290 data_blob_free(&ticket);
292 if (!NT_STATUS_IS_OK(ret)) {
293 #if 0
294 /* Experiment that failed.
295 * See "only happens with a KDC" comment below. */
297 if (NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
300 * Windows in this case returns
301 * NT_STATUS_MORE_PROCESSING_REQUIRED
302 * with a negTokenTarg blob containing an krb5_error
303 * struct ASN1 encoded containing KRB5KRB_AP_ERR_SKEW.
304 * The client then fixes its clock and continues rather
305 * than giving an error. JRA.
306 * -- Looks like this only happens with a KDC. JRA.
309 bool ok = make_krb5_skew_error(&ap_rep);
310 if (!ok) {
311 talloc_destroy(mem_ctx);
312 return ERROR_NT(nt_status_squash(
313 NT_STATUS_LOGON_FAILURE));
315 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep,
316 TOK_ID_KRB_ERROR);
317 response = spnego_gen_auth_response(&ap_rep_wrapped,
318 ret, OID_KERBEROS5_OLD);
319 reply_sesssetup_blob(conn, inbuf, outbuf, response,
320 NT_STATUS_MORE_PROCESSING_REQUIRED);
323 * In this one case we don't invalidate the
324 * intermediate vuid as we're expecting the client
325 * to re-use it for the next sessionsetupX packet. JRA.
328 *p_invalidate_vuid = False;
330 data_blob_free(&ap_rep);
331 data_blob_free(&ap_rep_wrapped);
332 data_blob_free(&response);
333 talloc_destroy(mem_ctx);
334 return -1; /* already replied */
336 #else
337 if (!NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
338 ret = NT_STATUS_LOGON_FAILURE;
340 #endif
341 DEBUG(1,("Failed to verify incoming ticket with error %s!\n",
342 nt_errstr(ret)));
343 talloc_destroy(mem_ctx);
344 reply_nterror(req, nt_status_squash(ret));
345 return;
348 DEBUG(3,("Ticket name is [%s]\n", client));
350 p = strchr_m(client, '@');
351 if (!p) {
352 DEBUG(3,("Doesn't look like a valid principal\n"));
353 data_blob_free(&ap_rep);
354 data_blob_free(&session_key);
355 talloc_destroy(mem_ctx);
356 reply_nterror(req,nt_status_squash(NT_STATUS_LOGON_FAILURE));
357 return;
360 *p = 0;
362 /* save the PAC data if we have it */
364 if (pac_data) {
365 logon_info = get_logon_info_from_pac(pac_data);
366 if (logon_info) {
367 netsamlogon_cache_store( client, &logon_info->info3 );
371 if (!strequal(p+1, lp_realm())) {
372 DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1));
373 if (!lp_allow_trusted_domains()) {
374 data_blob_free(&ap_rep);
375 data_blob_free(&session_key);
376 talloc_destroy(mem_ctx);
377 reply_nterror(req, nt_status_squash(
378 NT_STATUS_LOGON_FAILURE));
379 return;
383 /* this gives a fully qualified user name (ie. with full realm).
384 that leads to very long usernames, but what else can we do? */
386 domain = p+1;
388 if (logon_info && logon_info->info3.base.domain.string) {
389 fstrcpy(netbios_domain_name,
390 logon_info->info3.base.domain.string);
391 domain = netbios_domain_name;
392 DEBUG(10, ("Mapped to [%s] (using PAC)\n", domain));
394 } else {
396 /* If we have winbind running, we can (and must) shorten the
397 username by using the short netbios name. Otherwise we will
398 have inconsistent user names. With Kerberos, we get the
399 fully qualified realm, with ntlmssp we get the short
400 name. And even w2k3 does use ntlmssp if you for example
401 connect to an ip address. */
403 wbcErr wbc_status;
404 struct wbcDomainInfo *info = NULL;
406 DEBUG(10, ("Mapping [%s] to short name\n", domain));
408 wbc_status = wbcDomainInfo(domain, &info);
410 if (WBC_ERROR_IS_OK(wbc_status)) {
412 fstrcpy(netbios_domain_name,
413 info->short_name);
415 wbcFreeMemory(info);
416 domain = netbios_domain_name;
417 DEBUG(10, ("Mapped to [%s] (using Winbind)\n", domain));
418 } else {
419 DEBUG(3, ("Could not find short name: %s\n",
420 wbcErrorString(wbc_status)));
424 fstr_sprintf(user, "%s%c%s", domain, *lp_winbind_separator(), client);
426 /* lookup the passwd struct, create a new user if necessary */
428 username_was_mapped = map_username( user );
430 pw = smb_getpwnam( mem_ctx, user, real_username, True );
432 if (pw) {
433 /* if a real user check pam account restrictions */
434 /* only really perfomed if "obey pam restriction" is true */
435 /* do this before an eventual mapping to guest occurs */
436 ret = smb_pam_accountcheck(pw->pw_name);
437 if ( !NT_STATUS_IS_OK(ret)) {
438 DEBUG(1,("PAM account restriction "
439 "prevents user login\n"));
440 data_blob_free(&ap_rep);
441 data_blob_free(&session_key);
442 TALLOC_FREE(mem_ctx);
443 reply_nterror(req, nt_status_squash(ret));
444 return;
448 if (!pw) {
450 /* this was originally the behavior of Samba 2.2, if a user
451 did not have a local uid but has been authenticated, then
452 map them to a guest account */
454 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID){
455 map_domainuser_to_guest = True;
456 fstrcpy(user,lp_guestaccount());
457 pw = smb_getpwnam( mem_ctx, user, real_username, True );
460 /* extra sanity check that the guest account is valid */
462 if ( !pw ) {
463 DEBUG(1,("Username %s is invalid on this system\n",
464 user));
465 data_blob_free(&ap_rep);
466 data_blob_free(&session_key);
467 TALLOC_FREE(mem_ctx);
468 reply_nterror(req, nt_status_squash(
469 NT_STATUS_LOGON_FAILURE));
470 return;
474 /* setup the string used by %U */
476 sub_set_smb_name( real_username );
477 reload_services(True);
479 if ( map_domainuser_to_guest ) {
480 make_server_info_guest(NULL, &server_info);
481 } else if (logon_info) {
482 /* pass the unmapped username here since map_username()
483 will be called again from inside make_server_info_info3() */
485 ret = make_server_info_info3(mem_ctx, client, domain,
486 &server_info, &logon_info->info3);
487 if ( !NT_STATUS_IS_OK(ret) ) {
488 DEBUG(1,("make_server_info_info3 failed: %s!\n",
489 nt_errstr(ret)));
490 data_blob_free(&ap_rep);
491 data_blob_free(&session_key);
492 TALLOC_FREE(mem_ctx);
493 reply_nterror(req, nt_status_squash(ret));
494 return;
497 } else {
498 ret = make_server_info_pw(&server_info, real_username, pw);
500 if ( !NT_STATUS_IS_OK(ret) ) {
501 DEBUG(1,("make_server_info_pw failed: %s!\n",
502 nt_errstr(ret)));
503 data_blob_free(&ap_rep);
504 data_blob_free(&session_key);
505 TALLOC_FREE(mem_ctx);
506 reply_nterror(req, nt_status_squash(ret));
507 return;
510 /* make_server_info_pw does not set the domain. Without this
511 * we end up with the local netbios name in substitutions for
512 * %D. */
514 if (server_info->sam_account != NULL) {
515 pdb_set_domain(server_info->sam_account,
516 domain, PDB_SET);
520 server_info->nss_token |= username_was_mapped;
522 /* we need to build the token for the user. make_server_info_guest()
523 already does this */
525 if ( !server_info->ptok ) {
526 ret = create_local_token( server_info );
527 if ( !NT_STATUS_IS_OK(ret) ) {
528 DEBUG(10,("failed to create local token: %s\n",
529 nt_errstr(ret)));
530 data_blob_free(&ap_rep);
531 data_blob_free(&session_key);
532 TALLOC_FREE( mem_ctx );
533 TALLOC_FREE( server_info );
534 reply_nterror(req, nt_status_squash(ret));
535 return;
539 if (!is_partial_auth_vuid(sess_vuid)) {
540 sess_vuid = register_initial_vuid();
543 data_blob_free(&server_info->user_session_key);
544 server_info->user_session_key = session_key;
545 session_key = data_blob_null;
547 /* register_existing_vuid keeps the server info */
548 /* register_existing_vuid takes ownership of session_key on success,
549 * no need to free after this on success. A better interface would copy
550 * it.... */
552 sess_vuid = register_existing_vuid(sess_vuid,
553 server_info,
554 nullblob,
555 client);
557 reply_outbuf(req, 4, 0);
558 SSVAL(req->outbuf,smb_uid,sess_vuid);
560 if (sess_vuid == UID_FIELD_INVALID ) {
561 ret = NT_STATUS_LOGON_FAILURE;
562 } else {
563 /* current_user_info is changed on new vuid */
564 reload_services( True );
566 SSVAL(req->outbuf, smb_vwv3, 0);
568 if (server_info->guest) {
569 SSVAL(req->outbuf,smb_vwv2,1);
572 SSVAL(req->outbuf, smb_uid, sess_vuid);
574 sessionsetup_start_signing_engine(server_info, req->inbuf);
575 /* Successful logon. Keep this vuid. */
576 *p_invalidate_vuid = False;
579 /* wrap that up in a nice GSS-API wrapping */
580 if (NT_STATUS_IS_OK(ret)) {
581 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep,
582 TOK_ID_KRB_AP_REP);
583 } else {
584 ap_rep_wrapped = data_blob_null;
586 response = spnego_gen_auth_response(&ap_rep_wrapped, ret,
587 mechOID);
588 reply_sesssetup_blob(req, response, ret);
590 data_blob_free(&ap_rep);
591 data_blob_free(&ap_rep_wrapped);
592 data_blob_free(&response);
593 TALLOC_FREE(mem_ctx);
596 #endif
598 /****************************************************************************
599 Send a session setup reply, wrapped in SPNEGO.
600 Get vuid and check first.
601 End the NTLMSSP exchange context if we are OK/complete fail
602 This should be split into two functions, one to handle each
603 leg of the NTLM auth steps.
604 ***************************************************************************/
606 static void reply_spnego_ntlmssp(struct smb_request *req,
607 uint16 vuid,
608 AUTH_NTLMSSP_STATE **auth_ntlmssp_state,
609 DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status,
610 const char *OID,
611 bool wrap)
613 DATA_BLOB response;
614 struct auth_serversupplied_info *server_info = NULL;
616 if (NT_STATUS_IS_OK(nt_status)) {
617 server_info = (*auth_ntlmssp_state)->server_info;
618 } else {
619 nt_status = do_map_to_guest(nt_status,
620 &server_info,
621 (*auth_ntlmssp_state)->ntlmssp_state->user,
622 (*auth_ntlmssp_state)->ntlmssp_state->domain);
625 reply_outbuf(req, 4, 0);
627 SSVAL(req->outbuf, smb_uid, vuid);
629 if (NT_STATUS_IS_OK(nt_status)) {
630 DATA_BLOB nullblob = data_blob_null;
632 if (!is_partial_auth_vuid(vuid)) {
633 nt_status = NT_STATUS_LOGON_FAILURE;
634 goto out;
637 data_blob_free(&server_info->user_session_key);
638 server_info->user_session_key =
639 data_blob_talloc(
640 server_info,
641 (*auth_ntlmssp_state)->ntlmssp_state->session_key.data,
642 (*auth_ntlmssp_state)->ntlmssp_state->session_key.length);
644 /* register_existing_vuid keeps the server info */
645 if (register_existing_vuid(vuid,
646 server_info, nullblob,
647 (*auth_ntlmssp_state)->ntlmssp_state->user) !=
648 vuid) {
649 nt_status = NT_STATUS_LOGON_FAILURE;
650 goto out;
653 (*auth_ntlmssp_state)->server_info = NULL;
655 /* current_user_info is changed on new vuid */
656 reload_services( True );
658 SSVAL(req->outbuf, smb_vwv3, 0);
660 if (server_info->guest) {
661 SSVAL(req->outbuf,smb_vwv2,1);
664 sessionsetup_start_signing_engine(server_info,
665 (uint8 *)req->inbuf);
668 out:
670 if (wrap) {
671 response = spnego_gen_auth_response(ntlmssp_blob,
672 nt_status, OID);
673 } else {
674 response = *ntlmssp_blob;
677 reply_sesssetup_blob(req, response, nt_status);
678 if (wrap) {
679 data_blob_free(&response);
682 /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
683 and the other end, that we are not finished yet. */
685 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
686 /* NB. This is *NOT* an error case. JRA */
687 auth_ntlmssp_end(auth_ntlmssp_state);
688 if (!NT_STATUS_IS_OK(nt_status)) {
689 /* Kill the intermediate vuid */
690 invalidate_vuid(vuid);
695 /****************************************************************************
696 Is this a krb5 mechanism ?
697 ****************************************************************************/
699 NTSTATUS parse_spnego_mechanisms(DATA_BLOB blob_in,
700 DATA_BLOB *pblob_out,
701 char **kerb_mechOID)
703 char *OIDs[ASN1_MAX_OIDS];
704 int i;
705 NTSTATUS ret = NT_STATUS_OK;
707 *kerb_mechOID = NULL;
709 /* parse out the OIDs and the first sec blob */
710 if (!parse_negTokenTarg(blob_in, OIDs, pblob_out)) {
711 return NT_STATUS_LOGON_FAILURE;
714 /* only look at the first OID for determining the mechToken --
715 according to RFC2478, we should choose the one we want
716 and renegotiate, but i smell a client bug here..
718 Problem observed when connecting to a member (samba box)
719 of an AD domain as a user in a Samba domain. Samba member
720 server sent back krb5/mskrb5/ntlmssp as mechtypes, but the
721 client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an
722 NTLMSSP mechtoken. --jerry */
724 #ifdef HAVE_KRB5
725 if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||
726 strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
727 *kerb_mechOID = SMB_STRDUP(OIDs[0]);
728 if (*kerb_mechOID == NULL) {
729 ret = NT_STATUS_NO_MEMORY;
732 #endif
734 for (i=0;OIDs[i];i++) {
735 DEBUG(5,("parse_spnego_mechanisms: Got OID %s\n", OIDs[i]));
736 talloc_free(OIDs[i]);
738 return ret;
741 /****************************************************************************
742 Fall back from krb5 to NTLMSSP.
743 ****************************************************************************/
745 static void reply_spnego_downgrade_to_ntlmssp(struct smb_request *req,
746 uint16 vuid)
748 DATA_BLOB response;
750 reply_outbuf(req, 4, 0);
751 SSVAL(req->outbuf,smb_uid,vuid);
753 DEBUG(3,("reply_spnego_downgrade_to_ntlmssp: Got krb5 ticket in SPNEGO "
754 "but set to downgrade to NTLMSSP\n"));
756 response = spnego_gen_auth_response(NULL,
757 NT_STATUS_MORE_PROCESSING_REQUIRED,
758 OID_NTLMSSP);
759 reply_sesssetup_blob(req, response, NT_STATUS_MORE_PROCESSING_REQUIRED);
760 data_blob_free(&response);
763 /****************************************************************************
764 Reply to a session setup spnego negotiate packet.
765 ****************************************************************************/
767 static void reply_spnego_negotiate(struct smb_request *req,
768 uint16 vuid,
769 DATA_BLOB blob1,
770 AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
772 DATA_BLOB secblob;
773 DATA_BLOB chal;
774 char *kerb_mech = NULL;
775 NTSTATUS status;
777 status = parse_spnego_mechanisms(blob1, &secblob, &kerb_mech);
778 if (!NT_STATUS_IS_OK(status)) {
779 /* Kill the intermediate vuid */
780 invalidate_vuid(vuid);
781 reply_nterror(req, nt_status_squash(status));
782 return;
785 DEBUG(3,("reply_spnego_negotiate: Got secblob of size %lu\n",
786 (unsigned long)secblob.length));
788 #ifdef HAVE_KRB5
789 if (kerb_mech && ((lp_security()==SEC_ADS) ||
790 USE_KERBEROS_KEYTAB) ) {
791 bool destroy_vuid = True;
792 reply_spnego_kerberos(req, &secblob, kerb_mech,
793 vuid, &destroy_vuid);
794 data_blob_free(&secblob);
795 if (destroy_vuid) {
796 /* Kill the intermediate vuid */
797 invalidate_vuid(vuid);
799 SAFE_FREE(kerb_mech);
800 return;
802 #endif
804 if (*auth_ntlmssp_state) {
805 auth_ntlmssp_end(auth_ntlmssp_state);
808 if (kerb_mech) {
809 data_blob_free(&secblob);
810 /* The mechtoken is a krb5 ticket, but
811 * we need to fall back to NTLM. */
812 reply_spnego_downgrade_to_ntlmssp(req, vuid);
813 SAFE_FREE(kerb_mech);
814 return;
817 status = auth_ntlmssp_start(auth_ntlmssp_state);
818 if (!NT_STATUS_IS_OK(status)) {
819 /* Kill the intermediate vuid */
820 invalidate_vuid(vuid);
821 reply_nterror(req, nt_status_squash(status));
822 return;
825 status = auth_ntlmssp_update(*auth_ntlmssp_state,
826 secblob, &chal);
828 data_blob_free(&secblob);
830 reply_spnego_ntlmssp(req, vuid, auth_ntlmssp_state,
831 &chal, status, OID_NTLMSSP, true);
833 data_blob_free(&chal);
835 /* already replied */
836 return;
839 /****************************************************************************
840 Reply to a session setup spnego auth packet.
841 ****************************************************************************/
843 static void reply_spnego_auth(struct smb_request *req,
844 uint16 vuid,
845 DATA_BLOB blob1,
846 AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
848 DATA_BLOB auth = data_blob_null;
849 DATA_BLOB auth_reply = data_blob_null;
850 DATA_BLOB secblob = data_blob_null;
851 NTSTATUS status = NT_STATUS_LOGON_FAILURE;
853 if (!spnego_parse_auth(blob1, &auth)) {
854 #if 0
855 file_save("auth.dat", blob1.data, blob1.length);
856 #endif
857 /* Kill the intermediate vuid */
858 invalidate_vuid(vuid);
860 reply_nterror(req, nt_status_squash(
861 NT_STATUS_LOGON_FAILURE));
862 return;
865 if (auth.data[0] == ASN1_APPLICATION(0)) {
866 /* Might be a second negTokenTarg packet */
867 char *kerb_mech = NULL;
869 status = parse_spnego_mechanisms(auth, &secblob, &kerb_mech);
871 if (!NT_STATUS_IS_OK(status)) {
872 /* Kill the intermediate vuid */
873 invalidate_vuid(vuid);
874 reply_nterror(req, nt_status_squash(status));
875 return;
878 DEBUG(3,("reply_spnego_auth: Got secblob of size %lu\n",
879 (unsigned long)secblob.length));
880 #ifdef HAVE_KRB5
881 if (kerb_mech && ((lp_security()==SEC_ADS) ||
882 USE_KERBEROS_KEYTAB)) {
883 bool destroy_vuid = True;
884 reply_spnego_kerberos(req, &secblob, kerb_mech,
885 vuid, &destroy_vuid);
886 data_blob_free(&secblob);
887 data_blob_free(&auth);
888 if (destroy_vuid) {
889 /* Kill the intermediate vuid */
890 invalidate_vuid(vuid);
892 SAFE_FREE(kerb_mech);
893 return;
895 #endif
896 /* Can't blunder into NTLMSSP auth if we have
897 * a krb5 ticket. */
899 if (kerb_mech) {
900 /* Kill the intermediate vuid */
901 invalidate_vuid(vuid);
902 DEBUG(3,("reply_spnego_auth: network "
903 "misconfiguration, client sent us a "
904 "krb5 ticket and kerberos security "
905 "not enabled\n"));
906 reply_nterror(req, nt_status_squash(
907 NT_STATUS_LOGON_FAILURE));
908 SAFE_FREE(kerb_mech);
912 /* If we get here it wasn't a negTokenTarg auth packet. */
913 data_blob_free(&secblob);
915 if (!*auth_ntlmssp_state) {
916 status = auth_ntlmssp_start(auth_ntlmssp_state);
917 if (!NT_STATUS_IS_OK(status)) {
918 /* Kill the intermediate vuid */
919 invalidate_vuid(vuid);
920 reply_nterror(req, nt_status_squash(status));
921 return;
925 status = auth_ntlmssp_update(*auth_ntlmssp_state,
926 auth, &auth_reply);
928 data_blob_free(&auth);
930 /* Don't send the mechid as we've already sent this (RFC4178). */
932 reply_spnego_ntlmssp(req, vuid,
933 auth_ntlmssp_state,
934 &auth_reply, status, NULL, true);
936 data_blob_free(&auth_reply);
938 /* and tell smbd that we have already replied to this packet */
939 return;
942 /****************************************************************************
943 Delete an entry on the list.
944 ****************************************************************************/
946 static void delete_partial_auth(struct pending_auth_data *pad)
948 if (!pad) {
949 return;
951 DLIST_REMOVE(pd_list, pad);
952 data_blob_free(&pad->partial_data);
953 SAFE_FREE(pad);
956 /****************************************************************************
957 Search for a partial SPNEGO auth fragment matching an smbpid.
958 ****************************************************************************/
960 static struct pending_auth_data *get_pending_auth_data(uint16 smbpid)
962 struct pending_auth_data *pad;
964 for (pad = pd_list; pad; pad = pad->next) {
965 if (pad->smbpid == smbpid) {
966 break;
969 return pad;
972 /****************************************************************************
973 Check the size of an SPNEGO blob. If we need more return
974 NT_STATUS_MORE_PROCESSING_REQUIRED, else return NT_STATUS_OK. Don't allow
975 the blob to be more than 64k.
976 ****************************************************************************/
978 static NTSTATUS check_spnego_blob_complete(uint16 smbpid, uint16 vuid,
979 DATA_BLOB *pblob)
981 struct pending_auth_data *pad = NULL;
982 ASN1_DATA *data;
983 size_t needed_len = 0;
985 pad = get_pending_auth_data(smbpid);
987 /* Ensure we have some data. */
988 if (pblob->length == 0) {
989 /* Caller can cope. */
990 DEBUG(2,("check_spnego_blob_complete: zero blob length !\n"));
991 delete_partial_auth(pad);
992 return NT_STATUS_OK;
995 /* Were we waiting for more data ? */
996 if (pad) {
997 DATA_BLOB tmp_blob;
998 size_t copy_len = MIN(65536, pblob->length);
1000 /* Integer wrap paranoia.... */
1002 if (pad->partial_data.length + copy_len <
1003 pad->partial_data.length ||
1004 pad->partial_data.length + copy_len < copy_len) {
1006 DEBUG(2,("check_spnego_blob_complete: integer wrap "
1007 "pad->partial_data.length = %u, "
1008 "copy_len = %u\n",
1009 (unsigned int)pad->partial_data.length,
1010 (unsigned int)copy_len ));
1012 delete_partial_auth(pad);
1013 return NT_STATUS_INVALID_PARAMETER;
1016 DEBUG(10,("check_spnego_blob_complete: "
1017 "pad->partial_data.length = %u, "
1018 "pad->needed_len = %u, "
1019 "copy_len = %u, "
1020 "pblob->length = %u,\n",
1021 (unsigned int)pad->partial_data.length,
1022 (unsigned int)pad->needed_len,
1023 (unsigned int)copy_len,
1024 (unsigned int)pblob->length ));
1026 tmp_blob = data_blob(NULL,
1027 pad->partial_data.length + copy_len);
1029 /* Concatenate the two (up to copy_len) bytes. */
1030 memcpy(tmp_blob.data,
1031 pad->partial_data.data,
1032 pad->partial_data.length);
1033 memcpy(tmp_blob.data + pad->partial_data.length,
1034 pblob->data,
1035 copy_len);
1037 /* Replace the partial data. */
1038 data_blob_free(&pad->partial_data);
1039 pad->partial_data = tmp_blob;
1040 ZERO_STRUCT(tmp_blob);
1042 /* Are we done ? */
1043 if (pblob->length >= pad->needed_len) {
1044 /* Yes, replace pblob. */
1045 data_blob_free(pblob);
1046 *pblob = pad->partial_data;
1047 ZERO_STRUCT(pad->partial_data);
1048 delete_partial_auth(pad);
1049 return NT_STATUS_OK;
1052 /* Still need more data. */
1053 pad->needed_len -= copy_len;
1054 return NT_STATUS_MORE_PROCESSING_REQUIRED;
1057 if ((pblob->data[0] != ASN1_APPLICATION(0)) &&
1058 (pblob->data[0] != ASN1_CONTEXT(1))) {
1059 /* Not something we can determine the
1060 * length of.
1062 return NT_STATUS_OK;
1065 /* This is a new SPNEGO sessionsetup - see if
1066 * the data given in this blob is enough.
1069 data = asn1_init(NULL);
1070 if (data == NULL) {
1071 return NT_STATUS_NO_MEMORY;
1074 asn1_load(data, *pblob);
1075 asn1_start_tag(data, pblob->data[0]);
1076 if (data->has_error || data->nesting == NULL) {
1077 asn1_free(data);
1078 /* Let caller catch. */
1079 return NT_STATUS_OK;
1082 /* Integer wrap paranoia.... */
1084 if (data->nesting->taglen + data->nesting->start < data->nesting->taglen ||
1085 data->nesting->taglen + data->nesting->start < data->nesting->start) {
1087 DEBUG(2,("check_spnego_blob_complete: integer wrap "
1088 "data.nesting->taglen = %u, "
1089 "data.nesting->start = %u\n",
1090 (unsigned int)data->nesting->taglen,
1091 (unsigned int)data->nesting->start ));
1093 asn1_free(data);
1094 return NT_STATUS_INVALID_PARAMETER;
1097 /* Total length of the needed asn1 is the tag length
1098 * plus the current offset. */
1100 needed_len = data->nesting->taglen + data->nesting->start;
1101 asn1_free(data);
1103 DEBUG(10,("check_spnego_blob_complete: needed_len = %u, "
1104 "pblob->length = %u\n",
1105 (unsigned int)needed_len,
1106 (unsigned int)pblob->length ));
1108 if (needed_len <= pblob->length) {
1109 /* Nothing to do - blob is complete. */
1110 return NT_STATUS_OK;
1113 /* Refuse the blob if it's bigger than 64k. */
1114 if (needed_len > 65536) {
1115 DEBUG(2,("check_spnego_blob_complete: needed_len "
1116 "too large (%u)\n",
1117 (unsigned int)needed_len ));
1118 return NT_STATUS_INVALID_PARAMETER;
1121 /* We must store this blob until complete. */
1122 if (!(pad = SMB_MALLOC_P(struct pending_auth_data))) {
1123 return NT_STATUS_NO_MEMORY;
1125 pad->needed_len = needed_len - pblob->length;
1126 pad->partial_data = data_blob(pblob->data, pblob->length);
1127 if (pad->partial_data.data == NULL) {
1128 SAFE_FREE(pad);
1129 return NT_STATUS_NO_MEMORY;
1131 pad->smbpid = smbpid;
1132 pad->vuid = vuid;
1133 DLIST_ADD(pd_list, pad);
1135 return NT_STATUS_MORE_PROCESSING_REQUIRED;
1138 /****************************************************************************
1139 Reply to a session setup command.
1140 conn POINTER CAN BE NULL HERE !
1141 ****************************************************************************/
1143 static void reply_sesssetup_and_X_spnego(struct smb_request *req)
1145 const uint8 *p;
1146 DATA_BLOB blob1;
1147 size_t bufrem;
1148 char *tmp;
1149 const char *native_os;
1150 const char *native_lanman;
1151 const char *primary_domain;
1152 const char *p2;
1153 uint16 data_blob_len = SVAL(req->vwv+7, 0);
1154 enum remote_arch_types ra_type = get_remote_arch();
1155 int vuid = req->vuid;
1156 user_struct *vuser = NULL;
1157 NTSTATUS status = NT_STATUS_OK;
1158 uint16 smbpid = req->smbpid;
1160 DEBUG(3,("Doing spnego session setup\n"));
1162 if (global_client_caps == 0) {
1163 global_client_caps = IVAL(req->vwv+10, 0);
1165 if (!(global_client_caps & CAP_STATUS32)) {
1166 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1171 p = req->buf;
1173 if (data_blob_len == 0) {
1174 /* an invalid request */
1175 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1176 return;
1179 bufrem = smbreq_bufrem(req, p);
1180 /* pull the spnego blob */
1181 blob1 = data_blob(p, MIN(bufrem, data_blob_len));
1183 #if 0
1184 file_save("negotiate.dat", blob1.data, blob1.length);
1185 #endif
1187 p2 = (char *)req->buf + blob1.length;
1189 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1190 STR_TERMINATE);
1191 native_os = tmp ? tmp : "";
1193 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1194 STR_TERMINATE);
1195 native_lanman = tmp ? tmp : "";
1197 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1198 STR_TERMINATE);
1199 primary_domain = tmp ? tmp : "";
1201 DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
1202 native_os, native_lanman, primary_domain));
1204 if ( ra_type == RA_WIN2K ) {
1205 /* Vista sets neither the OS or lanman strings */
1207 if ( !strlen(native_os) && !strlen(native_lanman) )
1208 set_remote_arch(RA_VISTA);
1210 /* Windows 2003 doesn't set the native lanman string,
1211 but does set primary domain which is a bug I think */
1213 if ( !strlen(native_lanman) ) {
1214 ra_lanman_string( primary_domain );
1215 } else {
1216 ra_lanman_string( native_lanman );
1220 /* Did we get a valid vuid ? */
1221 if (!is_partial_auth_vuid(vuid)) {
1222 /* No, then try and see if this is an intermediate sessionsetup
1223 * for a large SPNEGO packet. */
1224 struct pending_auth_data *pad = get_pending_auth_data(smbpid);
1225 if (pad) {
1226 DEBUG(10,("reply_sesssetup_and_X_spnego: found "
1227 "pending vuid %u\n",
1228 (unsigned int)pad->vuid ));
1229 vuid = pad->vuid;
1233 /* Do we have a valid vuid now ? */
1234 if (!is_partial_auth_vuid(vuid)) {
1235 /* No, start a new authentication setup. */
1236 vuid = register_initial_vuid();
1237 if (vuid == UID_FIELD_INVALID) {
1238 data_blob_free(&blob1);
1239 reply_nterror(req, nt_status_squash(
1240 NT_STATUS_INVALID_PARAMETER));
1241 return;
1245 vuser = get_partial_auth_user_struct(vuid);
1246 /* This MUST be valid. */
1247 if (!vuser) {
1248 smb_panic("reply_sesssetup_and_X_spnego: invalid vuid.");
1251 /* Large (greater than 4k) SPNEGO blobs are split into multiple
1252 * sessionsetup requests as the Windows limit on the security blob
1253 * field is 4k. Bug #4400. JRA.
1256 status = check_spnego_blob_complete(smbpid, vuid, &blob1);
1257 if (!NT_STATUS_IS_OK(status)) {
1258 if (!NT_STATUS_EQUAL(status,
1259 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1260 /* Real error - kill the intermediate vuid */
1261 invalidate_vuid(vuid);
1263 data_blob_free(&blob1);
1264 reply_nterror(req, nt_status_squash(status));
1265 return;
1268 if (blob1.data[0] == ASN1_APPLICATION(0)) {
1270 /* its a negTokenTarg packet */
1272 reply_spnego_negotiate(req, vuid, blob1,
1273 &vuser->auth_ntlmssp_state);
1274 data_blob_free(&blob1);
1275 return;
1278 if (blob1.data[0] == ASN1_CONTEXT(1)) {
1280 /* its a auth packet */
1282 reply_spnego_auth(req, vuid, blob1,
1283 &vuser->auth_ntlmssp_state);
1284 data_blob_free(&blob1);
1285 return;
1288 if (strncmp((char *)(blob1.data), "NTLMSSP", 7) == 0) {
1289 DATA_BLOB chal;
1291 if (!vuser->auth_ntlmssp_state) {
1292 status = auth_ntlmssp_start(&vuser->auth_ntlmssp_state);
1293 if (!NT_STATUS_IS_OK(status)) {
1294 /* Kill the intermediate vuid */
1295 invalidate_vuid(vuid);
1296 data_blob_free(&blob1);
1297 reply_nterror(req, nt_status_squash(status));
1298 return;
1302 status = auth_ntlmssp_update(vuser->auth_ntlmssp_state,
1303 blob1, &chal);
1305 data_blob_free(&blob1);
1307 reply_spnego_ntlmssp(req, vuid,
1308 &vuser->auth_ntlmssp_state,
1309 &chal, status, OID_NTLMSSP, false);
1310 data_blob_free(&chal);
1311 return;
1314 /* what sort of packet is this? */
1315 DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
1317 data_blob_free(&blob1);
1319 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1322 /****************************************************************************
1323 On new VC == 0, shutdown *all* old connections and users.
1324 It seems that only NT4.x does this. At W2K and above (XP etc.).
1325 a new session setup with VC==0 is ignored.
1326 ****************************************************************************/
1328 static int shutdown_other_smbds(struct db_record *rec,
1329 const struct connections_key *key,
1330 const struct connections_data *crec,
1331 void *private_data)
1333 const char *ip = (const char *)private_data;
1335 if (!process_exists(crec->pid)) {
1336 return 0;
1339 if (procid_is_me(&crec->pid)) {
1340 return 0;
1343 if (strcmp(ip, crec->addr) != 0) {
1344 return 0;
1347 DEBUG(0,("shutdown_other_smbds: shutting down pid %u "
1348 "(IP %s)\n", (unsigned int)procid_to_pid(&crec->pid), ip));
1350 messaging_send(smbd_messaging_context(), crec->pid, MSG_SHUTDOWN,
1351 &data_blob_null);
1352 return 0;
1355 static void setup_new_vc_session(void)
1357 char addr[INET6_ADDRSTRLEN];
1359 DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x "
1360 "compatible we would close all old resources.\n"));
1361 #if 0
1362 conn_close_all();
1363 invalidate_all_vuids();
1364 #endif
1365 if (lp_reset_on_zero_vc()) {
1366 connections_forall(shutdown_other_smbds,
1367 CONST_DISCARD(void *,
1368 client_addr(get_client_fd(),addr,sizeof(addr))));
1372 /****************************************************************************
1373 Reply to a session setup command.
1374 ****************************************************************************/
1376 void reply_sesssetup_and_X(struct smb_request *req)
1378 int sess_vuid;
1379 int smb_bufsize;
1380 DATA_BLOB lm_resp;
1381 DATA_BLOB nt_resp;
1382 DATA_BLOB plaintext_password;
1383 char *tmp;
1384 const char *user;
1385 fstring sub_user; /* Sainitised username for substituion */
1386 const char *domain;
1387 const char *native_os;
1388 const char *native_lanman;
1389 const char *primary_domain;
1390 auth_usersupplied_info *user_info = NULL;
1391 auth_serversupplied_info *server_info = NULL;
1392 uint16 smb_flag2 = req->flags2;
1394 NTSTATUS nt_status;
1396 bool doencrypt = global_encrypted_passwords_negotiated;
1398 START_PROFILE(SMBsesssetupX);
1400 ZERO_STRUCT(lm_resp);
1401 ZERO_STRUCT(nt_resp);
1402 ZERO_STRUCT(plaintext_password);
1404 DEBUG(3,("wct=%d flg2=0x%x\n", req->wct, req->flags2));
1406 /* a SPNEGO session setup has 12 command words, whereas a normal
1407 NT1 session setup has 13. See the cifs spec. */
1408 if (req->wct == 12 &&
1409 (req->flags2 & FLAGS2_EXTENDED_SECURITY)) {
1411 if (!global_spnego_negotiated) {
1412 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt "
1413 "at SPNEGO session setup when it was not "
1414 "negotiated.\n"));
1415 reply_nterror(req, nt_status_squash(
1416 NT_STATUS_LOGON_FAILURE));
1417 END_PROFILE(SMBsesssetupX);
1418 return;
1421 if (SVAL(req->vwv+4, 0) == 0) {
1422 setup_new_vc_session();
1425 reply_sesssetup_and_X_spnego(req);
1426 END_PROFILE(SMBsesssetupX);
1427 return;
1430 smb_bufsize = SVAL(req->vwv+2, 0);
1432 if (Protocol < PROTOCOL_NT1) {
1433 uint16 passlen1 = SVAL(req->vwv+7, 0);
1435 /* Never do NT status codes with protocols before NT1 as we
1436 * don't get client caps. */
1437 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1439 if ((passlen1 > MAX_PASS_LEN) || (passlen1 > req->buflen)) {
1440 reply_nterror(req, nt_status_squash(
1441 NT_STATUS_INVALID_PARAMETER));
1442 END_PROFILE(SMBsesssetupX);
1443 return;
1446 if (doencrypt) {
1447 lm_resp = data_blob(req->buf, passlen1);
1448 } else {
1449 plaintext_password = data_blob(req->buf, passlen1+1);
1450 /* Ensure null termination */
1451 plaintext_password.data[passlen1] = 0;
1454 srvstr_pull_req_talloc(talloc_tos(), req, &tmp,
1455 req->buf + passlen1, STR_TERMINATE);
1456 user = tmp ? tmp : "";
1458 domain = "";
1460 } else {
1461 uint16 passlen1 = SVAL(req->vwv+7, 0);
1462 uint16 passlen2 = SVAL(req->vwv+8, 0);
1463 enum remote_arch_types ra_type = get_remote_arch();
1464 const uint8_t *p = req->buf;
1465 const uint8_t *save_p = req->buf;
1466 uint16 byte_count;
1469 if(global_client_caps == 0) {
1470 global_client_caps = IVAL(req->vwv+11, 0);
1472 if (!(global_client_caps & CAP_STATUS32)) {
1473 remove_from_common_flags2(
1474 FLAGS2_32_BIT_ERROR_CODES);
1477 /* client_caps is used as final determination if
1478 * client is NT or Win95. This is needed to return
1479 * the correct error codes in some circumstances.
1482 if(ra_type == RA_WINNT || ra_type == RA_WIN2K ||
1483 ra_type == RA_WIN95) {
1484 if(!(global_client_caps & (CAP_NT_SMBS|
1485 CAP_STATUS32))) {
1486 set_remote_arch( RA_WIN95);
1491 if (!doencrypt) {
1492 /* both Win95 and WinNT stuff up the password
1493 * lengths for non-encrypting systems. Uggh.
1495 if passlen1==24 its a win95 system, and its setting
1496 the password length incorrectly. Luckily it still
1497 works with the default code because Win95 will null
1498 terminate the password anyway
1500 if passlen1>0 and passlen2>0 then maybe its a NT box
1501 and its setting passlen2 to some random value which
1502 really stuffs things up. we need to fix that one. */
1504 if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 &&
1505 passlen2 != 1) {
1506 passlen2 = 0;
1510 /* check for nasty tricks */
1511 if (passlen1 > MAX_PASS_LEN
1512 || passlen1 > smbreq_bufrem(req, p)) {
1513 reply_nterror(req, nt_status_squash(
1514 NT_STATUS_INVALID_PARAMETER));
1515 END_PROFILE(SMBsesssetupX);
1516 return;
1519 if (passlen2 > MAX_PASS_LEN
1520 || passlen2 > smbreq_bufrem(req, p+passlen1)) {
1521 reply_nterror(req, nt_status_squash(
1522 NT_STATUS_INVALID_PARAMETER));
1523 END_PROFILE(SMBsesssetupX);
1524 return;
1527 /* Save the lanman2 password and the NT md4 password. */
1529 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
1530 doencrypt = False;
1533 if (doencrypt) {
1534 lm_resp = data_blob(p, passlen1);
1535 nt_resp = data_blob(p+passlen1, passlen2);
1536 } else if (lp_security() != SEC_SHARE) {
1538 * In share level we should ignore any passwords, so
1539 * only read them if we're not.
1541 char *pass = NULL;
1542 bool unic= smb_flag2 & FLAGS2_UNICODE_STRINGS;
1544 if (unic && (passlen2 == 0) && passlen1) {
1545 /* Only a ascii plaintext password was sent. */
1546 (void)srvstr_pull_talloc(talloc_tos(),
1547 req->inbuf,
1548 req->flags2,
1549 &pass,
1550 req->buf,
1551 passlen1,
1552 STR_TERMINATE|STR_ASCII);
1553 } else {
1554 (void)srvstr_pull_talloc(talloc_tos(),
1555 req->inbuf,
1556 req->flags2,
1557 &pass,
1558 req->buf,
1559 unic ? passlen2 : passlen1,
1560 STR_TERMINATE);
1562 if (!pass) {
1563 reply_nterror(req, nt_status_squash(
1564 NT_STATUS_INVALID_PARAMETER));
1565 END_PROFILE(SMBsesssetupX);
1566 return;
1568 plaintext_password = data_blob(pass, strlen(pass)+1);
1571 p += passlen1 + passlen2;
1573 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1574 STR_TERMINATE);
1575 user = tmp ? tmp : "";
1577 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1578 STR_TERMINATE);
1579 domain = tmp ? tmp : "";
1581 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1582 STR_TERMINATE);
1583 native_os = tmp ? tmp : "";
1585 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1586 STR_TERMINATE);
1587 native_lanman = tmp ? tmp : "";
1589 /* not documented or decoded by Ethereal but there is one more
1590 * string in the extra bytes which is the same as the
1591 * PrimaryDomain when using extended security. Windows NT 4
1592 * and 2003 use this string to store the native lanman string.
1593 * Windows 9x does not include a string here at all so we have
1594 * to check if we have any extra bytes left */
1596 byte_count = SVAL(req->vwv+13, 0);
1597 if ( PTR_DIFF(p, save_p) < byte_count) {
1598 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1599 STR_TERMINATE);
1600 primary_domain = tmp ? tmp : "";
1601 } else {
1602 primary_domain = talloc_strdup(talloc_tos(), "null");
1605 DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s] "
1606 "PrimaryDomain=[%s]\n",
1607 domain, native_os, native_lanman, primary_domain));
1609 if ( ra_type == RA_WIN2K ) {
1610 if ( strlen(native_lanman) == 0 )
1611 ra_lanman_string( primary_domain );
1612 else
1613 ra_lanman_string( native_lanman );
1618 if (SVAL(req->vwv+4, 0) == 0) {
1619 setup_new_vc_session();
1622 DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n",
1623 domain, user, get_remote_machine_name()));
1625 if (*user) {
1626 if (global_spnego_negotiated) {
1628 /* This has to be here, because this is a perfectly
1629 * valid behaviour for guest logons :-( */
1631 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt "
1632 "at 'normal' session setup after "
1633 "negotiating spnego.\n"));
1634 reply_nterror(req, nt_status_squash(
1635 NT_STATUS_LOGON_FAILURE));
1636 END_PROFILE(SMBsesssetupX);
1637 return;
1639 fstrcpy(sub_user, user);
1640 } else {
1641 fstrcpy(sub_user, lp_guestaccount());
1644 sub_set_smb_name(sub_user);
1646 reload_services(True);
1648 if (lp_security() == SEC_SHARE) {
1649 /* In share level we should ignore any passwords */
1651 data_blob_free(&lm_resp);
1652 data_blob_free(&nt_resp);
1653 data_blob_clear_free(&plaintext_password);
1655 map_username(sub_user);
1656 add_session_user(sub_user);
1657 add_session_workgroup(domain);
1658 /* Then force it to null for the benfit of the code below */
1659 user = "";
1662 if (!*user) {
1664 nt_status = check_guest_password(&server_info);
1666 } else if (doencrypt) {
1667 if (!negprot_global_auth_context) {
1668 DEBUG(0, ("reply_sesssetup_and_X: Attempted encrypted "
1669 "session setup without negprot denied!\n"));
1670 reply_nterror(req, nt_status_squash(
1671 NT_STATUS_LOGON_FAILURE));
1672 END_PROFILE(SMBsesssetupX);
1673 return;
1675 nt_status = make_user_info_for_reply_enc(&user_info, user,
1676 domain,
1677 lm_resp, nt_resp);
1678 if (NT_STATUS_IS_OK(nt_status)) {
1679 nt_status = negprot_global_auth_context->check_ntlm_password(
1680 negprot_global_auth_context,
1681 user_info,
1682 &server_info);
1684 } else {
1685 struct auth_context *plaintext_auth_context = NULL;
1687 nt_status = make_auth_context_subsystem(
1688 &plaintext_auth_context);
1690 if (NT_STATUS_IS_OK(nt_status)) {
1691 uint8_t chal[8];
1693 plaintext_auth_context->get_ntlm_challenge(
1694 plaintext_auth_context, chal);
1696 if (!make_user_info_for_reply(&user_info,
1697 user, domain, chal,
1698 plaintext_password)) {
1699 nt_status = NT_STATUS_NO_MEMORY;
1702 if (NT_STATUS_IS_OK(nt_status)) {
1703 nt_status = plaintext_auth_context->check_ntlm_password(
1704 plaintext_auth_context,
1705 user_info,
1706 &server_info);
1708 (plaintext_auth_context->free)(
1709 &plaintext_auth_context);
1714 free_user_info(&user_info);
1716 if (!NT_STATUS_IS_OK(nt_status)) {
1717 nt_status = do_map_to_guest(nt_status, &server_info,
1718 user, domain);
1721 if (!NT_STATUS_IS_OK(nt_status)) {
1722 data_blob_free(&nt_resp);
1723 data_blob_free(&lm_resp);
1724 data_blob_clear_free(&plaintext_password);
1725 reply_nterror(req, nt_status_squash(nt_status));
1726 END_PROFILE(SMBsesssetupX);
1727 return;
1730 /* Ensure we can't possible take a code path leading to a
1731 * null defref. */
1732 if (!server_info) {
1733 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1734 END_PROFILE(SMBsesssetupX);
1735 return;
1738 if (!server_info->ptok) {
1739 nt_status = create_local_token(server_info);
1741 if (!NT_STATUS_IS_OK(nt_status)) {
1742 DEBUG(10, ("create_local_token failed: %s\n",
1743 nt_errstr(nt_status)));
1744 data_blob_free(&nt_resp);
1745 data_blob_free(&lm_resp);
1746 data_blob_clear_free(&plaintext_password);
1747 reply_nterror(req, nt_status_squash(nt_status));
1748 END_PROFILE(SMBsesssetupX);
1749 return;
1753 data_blob_clear_free(&plaintext_password);
1755 /* it's ok - setup a reply */
1756 reply_outbuf(req, 3, 0);
1757 if (Protocol >= PROTOCOL_NT1) {
1758 push_signature(&req->outbuf);
1759 /* perhaps grab OS version here?? */
1762 if (server_info->guest) {
1763 SSVAL(req->outbuf,smb_vwv2,1);
1766 /* register the name and uid as being validated, so further connections
1767 to a uid can get through without a password, on the same VC */
1769 if (lp_security() == SEC_SHARE) {
1770 sess_vuid = UID_FIELD_INVALID;
1771 TALLOC_FREE(server_info);
1772 } else {
1773 /* Ignore the initial vuid. */
1774 sess_vuid = register_initial_vuid();
1775 if (sess_vuid == UID_FIELD_INVALID) {
1776 data_blob_free(&nt_resp);
1777 data_blob_free(&lm_resp);
1778 reply_nterror(req, nt_status_squash(
1779 NT_STATUS_LOGON_FAILURE));
1780 END_PROFILE(SMBsesssetupX);
1781 return;
1783 /* register_existing_vuid keeps the server info */
1784 sess_vuid = register_existing_vuid(sess_vuid,
1785 server_info,
1786 nt_resp.data ? nt_resp : lm_resp,
1787 sub_user);
1788 if (sess_vuid == UID_FIELD_INVALID) {
1789 data_blob_free(&nt_resp);
1790 data_blob_free(&lm_resp);
1791 reply_nterror(req, nt_status_squash(
1792 NT_STATUS_LOGON_FAILURE));
1793 END_PROFILE(SMBsesssetupX);
1794 return;
1797 /* current_user_info is changed on new vuid */
1798 reload_services( True );
1800 sessionsetup_start_signing_engine(server_info, req->inbuf);
1803 data_blob_free(&nt_resp);
1804 data_blob_free(&lm_resp);
1806 SSVAL(req->outbuf,smb_uid,sess_vuid);
1807 SSVAL(req->inbuf,smb_uid,sess_vuid);
1808 req->vuid = sess_vuid;
1810 if (!done_sesssetup)
1811 max_send = MIN(max_send,smb_bufsize);
1813 done_sesssetup = True;
1815 END_PROFILE(SMBsesssetupX);
1816 chain_reply(req);
1817 return;