idl: rebuild drsuapi.idl
[Samba/aatanasov.git] / source3 / smbd / sesssetup.c
blob16ea2ebfa911b09a7798cdac0a0880abecbf4bf3
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"
29 extern enum protocol_types Protocol;
31 /* For split krb5 SPNEGO blobs. */
32 struct pending_auth_data {
33 struct pending_auth_data *prev, *next;
34 uint16 vuid; /* Tag for this entry. */
35 uint16 smbpid; /* Alternate tag for this entry. */
36 size_t needed_len;
37 DATA_BLOB partial_data;
41 on a logon error possibly map the error to success if "map to guest"
42 is set approriately
44 static NTSTATUS do_map_to_guest(NTSTATUS status,
45 auth_serversupplied_info **server_info,
46 const char *user, const char *domain)
48 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
49 if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) ||
50 (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) {
51 DEBUG(3,("No such user %s [%s] - using guest account\n",
52 user, domain));
53 status = make_server_info_guest(NULL, server_info);
57 if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
58 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) {
59 DEBUG(3,("Registered username %s for guest access\n",
60 user));
61 status = make_server_info_guest(NULL, server_info);
65 return status;
68 /****************************************************************************
69 Add the standard 'Samba' signature to the end of the session setup.
70 ****************************************************************************/
72 static int push_signature(uint8 **outbuf)
74 char *lanman;
75 int result, tmp;
77 result = 0;
79 tmp = message_push_string(outbuf, "Unix", STR_TERMINATE);
81 if (tmp == -1) return -1;
82 result += tmp;
84 if (asprintf(&lanman, "Samba %s", samba_version_string()) != -1) {
85 tmp = message_push_string(outbuf, lanman, STR_TERMINATE);
86 SAFE_FREE(lanman);
88 else {
89 tmp = message_push_string(outbuf, "Samba", STR_TERMINATE);
92 if (tmp == -1) return -1;
93 result += tmp;
95 tmp = message_push_string(outbuf, lp_workgroup(), STR_TERMINATE);
97 if (tmp == -1) return -1;
98 result += tmp;
100 return result;
103 /****************************************************************************
104 Send a security blob via a session setup reply.
105 ****************************************************************************/
107 static void reply_sesssetup_blob(struct smb_request *req,
108 DATA_BLOB blob,
109 NTSTATUS nt_status)
111 if (!NT_STATUS_IS_OK(nt_status) &&
112 !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
113 reply_nterror(req, nt_status_squash(nt_status));
114 return;
117 nt_status = nt_status_squash(nt_status);
118 SIVAL(req->outbuf, smb_rcls, NT_STATUS_V(nt_status));
119 SSVAL(req->outbuf, smb_vwv0, 0xFF); /* no chaining possible */
120 SSVAL(req->outbuf, smb_vwv3, blob.length);
122 if ((message_push_blob(&req->outbuf, blob) == -1)
123 || (push_signature(&req->outbuf) == -1)) {
124 reply_nterror(req, NT_STATUS_NO_MEMORY);
128 /****************************************************************************
129 Do a 'guest' logon, getting back the
130 ****************************************************************************/
132 static NTSTATUS check_guest_password(auth_serversupplied_info **server_info)
134 struct auth_context *auth_context;
135 auth_usersupplied_info *user_info = NULL;
137 NTSTATUS nt_status;
138 unsigned char chal[8];
140 ZERO_STRUCT(chal);
142 DEBUG(3,("Got anonymous request\n"));
144 if (!NT_STATUS_IS_OK(nt_status = make_auth_context_fixed(&auth_context,
145 chal))) {
146 return nt_status;
149 if (!make_user_info_guest(&user_info)) {
150 (auth_context->free)(&auth_context);
151 return NT_STATUS_NO_MEMORY;
154 nt_status = auth_context->check_ntlm_password(auth_context,
155 user_info,
156 server_info);
157 (auth_context->free)(&auth_context);
158 free_user_info(&user_info);
159 return nt_status;
163 #ifdef HAVE_KRB5
165 #if 0
166 /* Experiment that failed. See "only happens with a KDC" comment below. */
167 /****************************************************************************
168 Cerate a clock skew error blob for a Windows client.
169 ****************************************************************************/
171 static bool make_krb5_skew_error(DATA_BLOB *pblob_out)
173 krb5_context context = NULL;
174 krb5_error_code kerr = 0;
175 krb5_data reply;
176 krb5_principal host_princ = NULL;
177 char *host_princ_s = NULL;
178 bool ret = False;
180 *pblob_out = data_blob_null;
182 initialize_krb5_error_table();
183 kerr = krb5_init_context(&context);
184 if (kerr) {
185 return False;
187 /* Create server principal. */
188 asprintf(&host_princ_s, "%s$@%s", global_myname(), lp_realm());
189 if (!host_princ_s) {
190 goto out;
192 strlower_m(host_princ_s);
194 kerr = smb_krb5_parse_name(context, host_princ_s, &host_princ);
195 if (kerr) {
196 DEBUG(10,("make_krb5_skew_error: smb_krb5_parse_name failed "
197 "for name %s: Error %s\n",
198 host_princ_s, error_message(kerr) ));
199 goto out;
202 kerr = smb_krb5_mk_error(context, KRB5KRB_AP_ERR_SKEW,
203 host_princ, &reply);
204 if (kerr) {
205 DEBUG(10,("make_krb5_skew_error: smb_krb5_mk_error "
206 "failed: Error %s\n",
207 error_message(kerr) ));
208 goto out;
211 *pblob_out = data_blob(reply.data, reply.length);
212 kerberos_free_data_contents(context,&reply);
213 ret = True;
215 out:
217 if (host_princ_s) {
218 SAFE_FREE(host_princ_s);
220 if (host_princ) {
221 krb5_free_principal(context, host_princ);
223 krb5_free_context(context);
224 return ret;
226 #endif
228 /****************************************************************************
229 Reply to a session setup spnego negotiate packet for kerberos.
230 ****************************************************************************/
232 static void reply_spnego_kerberos(struct smb_request *req,
233 DATA_BLOB *secblob,
234 const char *mechOID,
235 uint16 vuid,
236 bool *p_invalidate_vuid)
238 TALLOC_CTX *mem_ctx;
239 DATA_BLOB ticket;
240 char *client, *p, *domain;
241 fstring netbios_domain_name;
242 struct passwd *pw;
243 fstring user;
244 int sess_vuid = req->vuid;
245 NTSTATUS ret = NT_STATUS_OK;
246 struct PAC_DATA *pac_data = NULL;
247 DATA_BLOB ap_rep, ap_rep_wrapped, response;
248 auth_serversupplied_info *server_info = NULL;
249 DATA_BLOB session_key = data_blob_null;
250 uint8 tok_id[2];
251 DATA_BLOB nullblob = data_blob_null;
252 fstring real_username;
253 bool map_domainuser_to_guest = False;
254 bool username_was_mapped;
255 struct PAC_LOGON_INFO *logon_info = NULL;
256 struct smbd_server_connection *sconn = smbd_server_conn;
258 ZERO_STRUCT(ticket);
259 ZERO_STRUCT(ap_rep);
260 ZERO_STRUCT(ap_rep_wrapped);
261 ZERO_STRUCT(response);
263 /* Normally we will always invalidate the intermediate vuid. */
264 *p_invalidate_vuid = True;
266 mem_ctx = talloc_init("reply_spnego_kerberos");
267 if (mem_ctx == NULL) {
268 reply_nterror(req, nt_status_squash(NT_STATUS_NO_MEMORY));
269 return;
272 if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) {
273 talloc_destroy(mem_ctx);
274 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
275 return;
278 ret = ads_verify_ticket(mem_ctx, lp_realm(), 0, &ticket,
279 &client, &pac_data, &ap_rep,
280 &session_key, True);
282 data_blob_free(&ticket);
284 if (!NT_STATUS_IS_OK(ret)) {
285 #if 0
286 /* Experiment that failed.
287 * See "only happens with a KDC" comment below. */
289 if (NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
292 * Windows in this case returns
293 * NT_STATUS_MORE_PROCESSING_REQUIRED
294 * with a negTokenTarg blob containing an krb5_error
295 * struct ASN1 encoded containing KRB5KRB_AP_ERR_SKEW.
296 * The client then fixes its clock and continues rather
297 * than giving an error. JRA.
298 * -- Looks like this only happens with a KDC. JRA.
301 bool ok = make_krb5_skew_error(&ap_rep);
302 if (!ok) {
303 talloc_destroy(mem_ctx);
304 return ERROR_NT(nt_status_squash(
305 NT_STATUS_LOGON_FAILURE));
307 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep,
308 TOK_ID_KRB_ERROR);
309 response = spnego_gen_auth_response(&ap_rep_wrapped,
310 ret, OID_KERBEROS5_OLD);
311 reply_sesssetup_blob(conn, inbuf, outbuf, response,
312 NT_STATUS_MORE_PROCESSING_REQUIRED);
315 * In this one case we don't invalidate the
316 * intermediate vuid as we're expecting the client
317 * to re-use it for the next sessionsetupX packet. JRA.
320 *p_invalidate_vuid = False;
322 data_blob_free(&ap_rep);
323 data_blob_free(&ap_rep_wrapped);
324 data_blob_free(&response);
325 talloc_destroy(mem_ctx);
326 return -1; /* already replied */
328 #else
329 if (!NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
330 ret = NT_STATUS_LOGON_FAILURE;
332 #endif
333 DEBUG(1,("Failed to verify incoming ticket with error %s!\n",
334 nt_errstr(ret)));
335 talloc_destroy(mem_ctx);
336 reply_nterror(req, nt_status_squash(ret));
337 return;
340 DEBUG(3,("Ticket name is [%s]\n", client));
342 p = strchr_m(client, '@');
343 if (!p) {
344 DEBUG(3,("Doesn't look like a valid principal\n"));
345 data_blob_free(&ap_rep);
346 data_blob_free(&session_key);
347 talloc_destroy(mem_ctx);
348 reply_nterror(req,nt_status_squash(NT_STATUS_LOGON_FAILURE));
349 return;
352 *p = 0;
354 /* save the PAC data if we have it */
356 if (pac_data) {
357 logon_info = get_logon_info_from_pac(pac_data);
358 if (logon_info) {
359 netsamlogon_cache_store( client, &logon_info->info3 );
363 if (!strequal(p+1, lp_realm())) {
364 DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1));
365 if (!lp_allow_trusted_domains()) {
366 data_blob_free(&ap_rep);
367 data_blob_free(&session_key);
368 talloc_destroy(mem_ctx);
369 reply_nterror(req, nt_status_squash(
370 NT_STATUS_LOGON_FAILURE));
371 return;
375 /* this gives a fully qualified user name (ie. with full realm).
376 that leads to very long usernames, but what else can we do? */
378 domain = p+1;
380 if (logon_info && logon_info->info3.base.domain.string) {
381 fstrcpy(netbios_domain_name,
382 logon_info->info3.base.domain.string);
383 domain = netbios_domain_name;
384 DEBUG(10, ("Mapped to [%s] (using PAC)\n", domain));
386 } else {
388 /* If we have winbind running, we can (and must) shorten the
389 username by using the short netbios name. Otherwise we will
390 have inconsistent user names. With Kerberos, we get the
391 fully qualified realm, with ntlmssp we get the short
392 name. And even w2k3 does use ntlmssp if you for example
393 connect to an ip address. */
395 wbcErr wbc_status;
396 struct wbcDomainInfo *info = NULL;
398 DEBUG(10, ("Mapping [%s] to short name\n", domain));
400 wbc_status = wbcDomainInfo(domain, &info);
402 if (WBC_ERROR_IS_OK(wbc_status)) {
404 fstrcpy(netbios_domain_name,
405 info->short_name);
407 wbcFreeMemory(info);
408 domain = netbios_domain_name;
409 DEBUG(10, ("Mapped to [%s] (using Winbind)\n", domain));
410 } else {
411 DEBUG(3, ("Could not find short name: %s\n",
412 wbcErrorString(wbc_status)));
416 fstr_sprintf(user, "%s%c%s", domain, *lp_winbind_separator(), client);
418 /* lookup the passwd struct, create a new user if necessary */
420 username_was_mapped = map_username(sconn, user);
422 pw = smb_getpwnam( mem_ctx, user, real_username, True );
424 if (pw) {
425 /* if a real user check pam account restrictions */
426 /* only really perfomed if "obey pam restriction" is true */
427 /* do this before an eventual mapping to guest occurs */
428 ret = smb_pam_accountcheck(pw->pw_name);
429 if ( !NT_STATUS_IS_OK(ret)) {
430 DEBUG(1,("PAM account restriction "
431 "prevents user login\n"));
432 data_blob_free(&ap_rep);
433 data_blob_free(&session_key);
434 TALLOC_FREE(mem_ctx);
435 reply_nterror(req, nt_status_squash(ret));
436 return;
440 if (!pw) {
442 /* this was originally the behavior of Samba 2.2, if a user
443 did not have a local uid but has been authenticated, then
444 map them to a guest account */
446 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID){
447 map_domainuser_to_guest = True;
448 fstrcpy(user,lp_guestaccount());
449 pw = smb_getpwnam( mem_ctx, user, real_username, True );
452 /* extra sanity check that the guest account is valid */
454 if ( !pw ) {
455 DEBUG(1,("Username %s is invalid on this system\n",
456 user));
457 data_blob_free(&ap_rep);
458 data_blob_free(&session_key);
459 TALLOC_FREE(mem_ctx);
460 reply_nterror(req, nt_status_squash(
461 NT_STATUS_LOGON_FAILURE));
462 return;
466 /* setup the string used by %U */
468 sub_set_smb_name( real_username );
469 reload_services(True);
471 if ( map_domainuser_to_guest ) {
472 make_server_info_guest(NULL, &server_info);
473 } else if (logon_info) {
474 /* pass the unmapped username here since map_username()
475 will be called again from inside make_server_info_info3() */
477 ret = make_server_info_info3(mem_ctx, client, domain,
478 &server_info, &logon_info->info3);
479 if ( !NT_STATUS_IS_OK(ret) ) {
480 DEBUG(1,("make_server_info_info3 failed: %s!\n",
481 nt_errstr(ret)));
482 data_blob_free(&ap_rep);
483 data_blob_free(&session_key);
484 TALLOC_FREE(mem_ctx);
485 reply_nterror(req, nt_status_squash(ret));
486 return;
489 } else {
490 ret = make_server_info_pw(&server_info, real_username, pw);
492 if ( !NT_STATUS_IS_OK(ret) ) {
493 DEBUG(1,("make_server_info_pw failed: %s!\n",
494 nt_errstr(ret)));
495 data_blob_free(&ap_rep);
496 data_blob_free(&session_key);
497 TALLOC_FREE(mem_ctx);
498 reply_nterror(req, nt_status_squash(ret));
499 return;
502 /* make_server_info_pw does not set the domain. Without this
503 * we end up with the local netbios name in substitutions for
504 * %D. */
506 if (server_info->sam_account != NULL) {
507 pdb_set_domain(server_info->sam_account,
508 domain, PDB_SET);
512 server_info->nss_token |= username_was_mapped;
514 /* we need to build the token for the user. make_server_info_guest()
515 already does this */
517 if ( !server_info->ptok ) {
518 ret = create_local_token( server_info );
519 if ( !NT_STATUS_IS_OK(ret) ) {
520 DEBUG(10,("failed to create local token: %s\n",
521 nt_errstr(ret)));
522 data_blob_free(&ap_rep);
523 data_blob_free(&session_key);
524 TALLOC_FREE( mem_ctx );
525 TALLOC_FREE( server_info );
526 reply_nterror(req, nt_status_squash(ret));
527 return;
531 if (!is_partial_auth_vuid(sconn, sess_vuid)) {
532 sess_vuid = register_initial_vuid(sconn);
535 data_blob_free(&server_info->user_session_key);
536 server_info->user_session_key = session_key;
537 session_key = data_blob_null;
539 /* register_existing_vuid keeps the server info */
540 /* register_existing_vuid takes ownership of session_key on success,
541 * no need to free after this on success. A better interface would copy
542 * it.... */
544 sess_vuid = register_existing_vuid(sconn,
545 sess_vuid,
546 server_info,
547 nullblob,
548 client);
550 reply_outbuf(req, 4, 0);
551 SSVAL(req->outbuf,smb_uid,sess_vuid);
553 if (sess_vuid == UID_FIELD_INVALID ) {
554 ret = NT_STATUS_LOGON_FAILURE;
555 } else {
556 /* current_user_info is changed on new vuid */
557 reload_services( True );
559 SSVAL(req->outbuf, smb_vwv3, 0);
561 if (server_info->guest) {
562 SSVAL(req->outbuf,smb_vwv2,1);
565 SSVAL(req->outbuf, smb_uid, sess_vuid);
567 /* Successful logon. Keep this vuid. */
568 *p_invalidate_vuid = False;
571 /* wrap that up in a nice GSS-API wrapping */
572 if (NT_STATUS_IS_OK(ret)) {
573 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep,
574 TOK_ID_KRB_AP_REP);
575 } else {
576 ap_rep_wrapped = data_blob_null;
578 response = spnego_gen_auth_response(&ap_rep_wrapped, ret,
579 mechOID);
580 reply_sesssetup_blob(req, response, ret);
582 data_blob_free(&ap_rep);
583 data_blob_free(&ap_rep_wrapped);
584 data_blob_free(&response);
585 TALLOC_FREE(mem_ctx);
588 #endif
590 /****************************************************************************
591 Send a session setup reply, wrapped in SPNEGO.
592 Get vuid and check first.
593 End the NTLMSSP exchange context if we are OK/complete fail
594 This should be split into two functions, one to handle each
595 leg of the NTLM auth steps.
596 ***************************************************************************/
598 static void reply_spnego_ntlmssp(struct smb_request *req,
599 uint16 vuid,
600 AUTH_NTLMSSP_STATE **auth_ntlmssp_state,
601 DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status,
602 const char *OID,
603 bool wrap)
605 DATA_BLOB response;
606 struct auth_serversupplied_info *server_info = NULL;
607 struct smbd_server_connection *sconn = smbd_server_conn;
609 if (NT_STATUS_IS_OK(nt_status)) {
610 server_info = (*auth_ntlmssp_state)->server_info;
611 } else {
612 nt_status = do_map_to_guest(nt_status,
613 &server_info,
614 (*auth_ntlmssp_state)->ntlmssp_state->user,
615 (*auth_ntlmssp_state)->ntlmssp_state->domain);
618 reply_outbuf(req, 4, 0);
620 SSVAL(req->outbuf, smb_uid, vuid);
622 if (NT_STATUS_IS_OK(nt_status)) {
623 DATA_BLOB nullblob = data_blob_null;
625 if (!is_partial_auth_vuid(sconn, vuid)) {
626 nt_status = NT_STATUS_LOGON_FAILURE;
627 goto out;
630 data_blob_free(&server_info->user_session_key);
631 server_info->user_session_key =
632 data_blob_talloc(
633 server_info,
634 (*auth_ntlmssp_state)->ntlmssp_state->session_key.data,
635 (*auth_ntlmssp_state)->ntlmssp_state->session_key.length);
637 /* register_existing_vuid keeps the server info */
638 if (register_existing_vuid(sconn, vuid,
639 server_info, nullblob,
640 (*auth_ntlmssp_state)->ntlmssp_state->user) !=
641 vuid) {
642 nt_status = NT_STATUS_LOGON_FAILURE;
643 goto out;
646 (*auth_ntlmssp_state)->server_info = NULL;
648 /* current_user_info is changed on new vuid */
649 reload_services( True );
651 SSVAL(req->outbuf, smb_vwv3, 0);
653 if (server_info->guest) {
654 SSVAL(req->outbuf,smb_vwv2,1);
658 out:
660 if (wrap) {
661 response = spnego_gen_auth_response(ntlmssp_blob,
662 nt_status, OID);
663 } else {
664 response = *ntlmssp_blob;
667 reply_sesssetup_blob(req, response, nt_status);
668 if (wrap) {
669 data_blob_free(&response);
672 /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
673 and the other end, that we are not finished yet. */
675 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
676 /* NB. This is *NOT* an error case. JRA */
677 auth_ntlmssp_end(auth_ntlmssp_state);
678 if (!NT_STATUS_IS_OK(nt_status)) {
679 /* Kill the intermediate vuid */
680 invalidate_vuid(sconn, vuid);
685 /****************************************************************************
686 Is this a krb5 mechanism ?
687 ****************************************************************************/
689 NTSTATUS parse_spnego_mechanisms(DATA_BLOB blob_in,
690 DATA_BLOB *pblob_out,
691 char **kerb_mechOID)
693 char *OIDs[ASN1_MAX_OIDS];
694 int i;
695 NTSTATUS ret = NT_STATUS_OK;
697 *kerb_mechOID = NULL;
699 /* parse out the OIDs and the first sec blob */
700 if (!parse_negTokenTarg(blob_in, OIDs, pblob_out)) {
701 return NT_STATUS_LOGON_FAILURE;
704 /* only look at the first OID for determining the mechToken --
705 according to RFC2478, we should choose the one we want
706 and renegotiate, but i smell a client bug here..
708 Problem observed when connecting to a member (samba box)
709 of an AD domain as a user in a Samba domain. Samba member
710 server sent back krb5/mskrb5/ntlmssp as mechtypes, but the
711 client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an
712 NTLMSSP mechtoken. --jerry */
714 #ifdef HAVE_KRB5
715 if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||
716 strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
717 *kerb_mechOID = SMB_STRDUP(OIDs[0]);
718 if (*kerb_mechOID == NULL) {
719 ret = NT_STATUS_NO_MEMORY;
722 #endif
724 for (i=0;OIDs[i];i++) {
725 DEBUG(5,("parse_spnego_mechanisms: Got OID %s\n", OIDs[i]));
726 talloc_free(OIDs[i]);
728 return ret;
731 /****************************************************************************
732 Fall back from krb5 to NTLMSSP.
733 ****************************************************************************/
735 static void reply_spnego_downgrade_to_ntlmssp(struct smb_request *req,
736 uint16 vuid)
738 DATA_BLOB response;
740 reply_outbuf(req, 4, 0);
741 SSVAL(req->outbuf,smb_uid,vuid);
743 DEBUG(3,("reply_spnego_downgrade_to_ntlmssp: Got krb5 ticket in SPNEGO "
744 "but set to downgrade to NTLMSSP\n"));
746 response = spnego_gen_auth_response(NULL,
747 NT_STATUS_MORE_PROCESSING_REQUIRED,
748 OID_NTLMSSP);
749 reply_sesssetup_blob(req, response, NT_STATUS_MORE_PROCESSING_REQUIRED);
750 data_blob_free(&response);
753 /****************************************************************************
754 Reply to a session setup spnego negotiate packet.
755 ****************************************************************************/
757 static void reply_spnego_negotiate(struct smb_request *req,
758 uint16 vuid,
759 DATA_BLOB blob1,
760 AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
762 DATA_BLOB secblob;
763 DATA_BLOB chal;
764 char *kerb_mech = NULL;
765 NTSTATUS status;
766 struct smbd_server_connection *sconn = smbd_server_conn;
768 status = parse_spnego_mechanisms(blob1, &secblob, &kerb_mech);
769 if (!NT_STATUS_IS_OK(status)) {
770 /* Kill the intermediate vuid */
771 invalidate_vuid(sconn, vuid);
772 reply_nterror(req, nt_status_squash(status));
773 return;
776 DEBUG(3,("reply_spnego_negotiate: Got secblob of size %lu\n",
777 (unsigned long)secblob.length));
779 #ifdef HAVE_KRB5
780 if (kerb_mech && ((lp_security()==SEC_ADS) ||
781 USE_KERBEROS_KEYTAB) ) {
782 bool destroy_vuid = True;
783 reply_spnego_kerberos(req, &secblob, kerb_mech,
784 vuid, &destroy_vuid);
785 data_blob_free(&secblob);
786 if (destroy_vuid) {
787 /* Kill the intermediate vuid */
788 invalidate_vuid(sconn, vuid);
790 SAFE_FREE(kerb_mech);
791 return;
793 #endif
795 if (*auth_ntlmssp_state) {
796 auth_ntlmssp_end(auth_ntlmssp_state);
799 if (kerb_mech) {
800 data_blob_free(&secblob);
801 /* The mechtoken is a krb5 ticket, but
802 * we need to fall back to NTLM. */
803 reply_spnego_downgrade_to_ntlmssp(req, vuid);
804 SAFE_FREE(kerb_mech);
805 return;
808 status = auth_ntlmssp_start(auth_ntlmssp_state);
809 if (!NT_STATUS_IS_OK(status)) {
810 /* Kill the intermediate vuid */
811 invalidate_vuid(sconn, vuid);
812 reply_nterror(req, nt_status_squash(status));
813 return;
816 status = auth_ntlmssp_update(*auth_ntlmssp_state,
817 secblob, &chal);
819 data_blob_free(&secblob);
821 reply_spnego_ntlmssp(req, vuid, auth_ntlmssp_state,
822 &chal, status, OID_NTLMSSP, true);
824 data_blob_free(&chal);
826 /* already replied */
827 return;
830 /****************************************************************************
831 Reply to a session setup spnego auth packet.
832 ****************************************************************************/
834 static void reply_spnego_auth(struct smb_request *req,
835 uint16 vuid,
836 DATA_BLOB blob1,
837 AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
839 DATA_BLOB auth = data_blob_null;
840 DATA_BLOB auth_reply = data_blob_null;
841 DATA_BLOB secblob = data_blob_null;
842 NTSTATUS status = NT_STATUS_LOGON_FAILURE;
843 struct smbd_server_connection *sconn = smbd_server_conn;
845 if (!spnego_parse_auth(blob1, &auth)) {
846 #if 0
847 file_save("auth.dat", blob1.data, blob1.length);
848 #endif
849 /* Kill the intermediate vuid */
850 invalidate_vuid(sconn, vuid);
852 reply_nterror(req, nt_status_squash(
853 NT_STATUS_LOGON_FAILURE));
854 return;
857 if (auth.data[0] == ASN1_APPLICATION(0)) {
858 /* Might be a second negTokenTarg packet */
859 char *kerb_mech = NULL;
861 status = parse_spnego_mechanisms(auth, &secblob, &kerb_mech);
863 if (!NT_STATUS_IS_OK(status)) {
864 /* Kill the intermediate vuid */
865 invalidate_vuid(sconn, vuid);
866 reply_nterror(req, nt_status_squash(status));
867 return;
870 DEBUG(3,("reply_spnego_auth: Got secblob of size %lu\n",
871 (unsigned long)secblob.length));
872 #ifdef HAVE_KRB5
873 if (kerb_mech && ((lp_security()==SEC_ADS) ||
874 USE_KERBEROS_KEYTAB)) {
875 bool destroy_vuid = True;
876 reply_spnego_kerberos(req, &secblob, kerb_mech,
877 vuid, &destroy_vuid);
878 data_blob_free(&secblob);
879 data_blob_free(&auth);
880 if (destroy_vuid) {
881 /* Kill the intermediate vuid */
882 invalidate_vuid(sconn, vuid);
884 SAFE_FREE(kerb_mech);
885 return;
887 #endif
888 /* Can't blunder into NTLMSSP auth if we have
889 * a krb5 ticket. */
891 if (kerb_mech) {
892 /* Kill the intermediate vuid */
893 invalidate_vuid(sconn, vuid);
894 DEBUG(3,("reply_spnego_auth: network "
895 "misconfiguration, client sent us a "
896 "krb5 ticket and kerberos security "
897 "not enabled\n"));
898 reply_nterror(req, nt_status_squash(
899 NT_STATUS_LOGON_FAILURE));
900 SAFE_FREE(kerb_mech);
904 /* If we get here it wasn't a negTokenTarg auth packet. */
905 data_blob_free(&secblob);
907 if (!*auth_ntlmssp_state) {
908 status = auth_ntlmssp_start(auth_ntlmssp_state);
909 if (!NT_STATUS_IS_OK(status)) {
910 /* Kill the intermediate vuid */
911 invalidate_vuid(sconn, vuid);
912 reply_nterror(req, nt_status_squash(status));
913 return;
917 status = auth_ntlmssp_update(*auth_ntlmssp_state,
918 auth, &auth_reply);
920 data_blob_free(&auth);
922 /* Don't send the mechid as we've already sent this (RFC4178). */
924 reply_spnego_ntlmssp(req, vuid,
925 auth_ntlmssp_state,
926 &auth_reply, status, NULL, true);
928 data_blob_free(&auth_reply);
930 /* and tell smbd that we have already replied to this packet */
931 return;
934 /****************************************************************************
935 Delete an entry on the list.
936 ****************************************************************************/
938 static void delete_partial_auth(struct smbd_server_connection *sconn,
939 struct pending_auth_data *pad)
941 if (!pad) {
942 return;
944 DLIST_REMOVE(sconn->smb1.pd_list, pad);
945 data_blob_free(&pad->partial_data);
946 SAFE_FREE(pad);
949 /****************************************************************************
950 Search for a partial SPNEGO auth fragment matching an smbpid.
951 ****************************************************************************/
953 static struct pending_auth_data *get_pending_auth_data(
954 struct smbd_server_connection *sconn,
955 uint16_t smbpid)
957 struct pending_auth_data *pad;
959 * NOTE: using the smbpid here is completely wrong...
960 * see [MS-SMB]
961 * 3.3.5.3 Receiving an SMB_COM_SESSION_SETUP_ANDX Request
963 for (pad = sconn->smb1.pd_list; pad; pad = pad->next) {
964 if (pad->smbpid == smbpid) {
965 break;
968 return pad;
971 /****************************************************************************
972 Check the size of an SPNEGO blob. If we need more return
973 NT_STATUS_MORE_PROCESSING_REQUIRED, else return NT_STATUS_OK. Don't allow
974 the blob to be more than 64k.
975 ****************************************************************************/
977 static NTSTATUS check_spnego_blob_complete(struct smbd_server_connection *sconn,
978 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(sconn, 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(sconn, 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(sconn, 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(sconn, 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(sconn->smb1.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;
1159 struct smbd_server_connection *sconn = smbd_server_conn;
1161 DEBUG(3,("Doing spnego session setup\n"));
1163 if (global_client_caps == 0) {
1164 global_client_caps = IVAL(req->vwv+10, 0);
1166 if (!(global_client_caps & CAP_STATUS32)) {
1167 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1172 p = req->buf;
1174 if (data_blob_len == 0) {
1175 /* an invalid request */
1176 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1177 return;
1180 bufrem = smbreq_bufrem(req, p);
1181 /* pull the spnego blob */
1182 blob1 = data_blob(p, MIN(bufrem, data_blob_len));
1184 #if 0
1185 file_save("negotiate.dat", blob1.data, blob1.length);
1186 #endif
1188 p2 = (char *)req->buf + data_blob_len;
1190 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1191 STR_TERMINATE);
1192 native_os = tmp ? tmp : "";
1194 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1195 STR_TERMINATE);
1196 native_lanman = tmp ? tmp : "";
1198 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1199 STR_TERMINATE);
1200 primary_domain = tmp ? tmp : "";
1202 DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
1203 native_os, native_lanman, primary_domain));
1205 if ( ra_type == RA_WIN2K ) {
1206 /* Vista sets neither the OS or lanman strings */
1208 if ( !strlen(native_os) && !strlen(native_lanman) )
1209 set_remote_arch(RA_VISTA);
1211 /* Windows 2003 doesn't set the native lanman string,
1212 but does set primary domain which is a bug I think */
1214 if ( !strlen(native_lanman) ) {
1215 ra_lanman_string( primary_domain );
1216 } else {
1217 ra_lanman_string( native_lanman );
1221 /* Did we get a valid vuid ? */
1222 if (!is_partial_auth_vuid(sconn, vuid)) {
1223 /* No, then try and see if this is an intermediate sessionsetup
1224 * for a large SPNEGO packet. */
1225 struct pending_auth_data *pad;
1226 pad = get_pending_auth_data(sconn, smbpid);
1227 if (pad) {
1228 DEBUG(10,("reply_sesssetup_and_X_spnego: found "
1229 "pending vuid %u\n",
1230 (unsigned int)pad->vuid ));
1231 vuid = pad->vuid;
1235 /* Do we have a valid vuid now ? */
1236 if (!is_partial_auth_vuid(sconn, vuid)) {
1237 /* No, start a new authentication setup. */
1238 vuid = register_initial_vuid(sconn);
1239 if (vuid == UID_FIELD_INVALID) {
1240 data_blob_free(&blob1);
1241 reply_nterror(req, nt_status_squash(
1242 NT_STATUS_INVALID_PARAMETER));
1243 return;
1247 vuser = get_partial_auth_user_struct(sconn, vuid);
1248 /* This MUST be valid. */
1249 if (!vuser) {
1250 smb_panic("reply_sesssetup_and_X_spnego: invalid vuid.");
1253 /* Large (greater than 4k) SPNEGO blobs are split into multiple
1254 * sessionsetup requests as the Windows limit on the security blob
1255 * field is 4k. Bug #4400. JRA.
1258 status = check_spnego_blob_complete(sconn, smbpid, vuid, &blob1);
1259 if (!NT_STATUS_IS_OK(status)) {
1260 if (!NT_STATUS_EQUAL(status,
1261 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1262 /* Real error - kill the intermediate vuid */
1263 invalidate_vuid(sconn, vuid);
1265 data_blob_free(&blob1);
1266 reply_nterror(req, nt_status_squash(status));
1267 return;
1270 if (blob1.data[0] == ASN1_APPLICATION(0)) {
1272 /* its a negTokenTarg packet */
1274 reply_spnego_negotiate(req, vuid, blob1,
1275 &vuser->auth_ntlmssp_state);
1276 data_blob_free(&blob1);
1277 return;
1280 if (blob1.data[0] == ASN1_CONTEXT(1)) {
1282 /* its a auth packet */
1284 reply_spnego_auth(req, vuid, blob1,
1285 &vuser->auth_ntlmssp_state);
1286 data_blob_free(&blob1);
1287 return;
1290 if (strncmp((char *)(blob1.data), "NTLMSSP", 7) == 0) {
1291 DATA_BLOB chal;
1293 if (!vuser->auth_ntlmssp_state) {
1294 status = auth_ntlmssp_start(&vuser->auth_ntlmssp_state);
1295 if (!NT_STATUS_IS_OK(status)) {
1296 /* Kill the intermediate vuid */
1297 invalidate_vuid(sconn, vuid);
1298 data_blob_free(&blob1);
1299 reply_nterror(req, nt_status_squash(status));
1300 return;
1304 status = auth_ntlmssp_update(vuser->auth_ntlmssp_state,
1305 blob1, &chal);
1307 data_blob_free(&blob1);
1309 reply_spnego_ntlmssp(req, vuid,
1310 &vuser->auth_ntlmssp_state,
1311 &chal, status, OID_NTLMSSP, false);
1312 data_blob_free(&chal);
1313 return;
1316 /* what sort of packet is this? */
1317 DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
1319 data_blob_free(&blob1);
1321 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1324 /****************************************************************************
1325 On new VC == 0, shutdown *all* old connections and users.
1326 It seems that only NT4.x does this. At W2K and above (XP etc.).
1327 a new session setup with VC==0 is ignored.
1328 ****************************************************************************/
1330 static int shutdown_other_smbds(struct db_record *rec,
1331 const struct connections_key *key,
1332 const struct connections_data *crec,
1333 void *private_data)
1335 const char *ip = (const char *)private_data;
1337 if (!process_exists(crec->pid)) {
1338 return 0;
1341 if (procid_is_me(&crec->pid)) {
1342 return 0;
1345 if (strcmp(ip, crec->addr) != 0) {
1346 return 0;
1349 DEBUG(0,("shutdown_other_smbds: shutting down pid %u "
1350 "(IP %s)\n", (unsigned int)procid_to_pid(&crec->pid), ip));
1352 messaging_send(smbd_messaging_context(), crec->pid, MSG_SHUTDOWN,
1353 &data_blob_null);
1354 return 0;
1357 static void setup_new_vc_session(void)
1359 char addr[INET6_ADDRSTRLEN];
1361 DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x "
1362 "compatible we would close all old resources.\n"));
1363 #if 0
1364 conn_close_all();
1365 invalidate_all_vuids();
1366 #endif
1367 if (lp_reset_on_zero_vc()) {
1368 connections_forall(shutdown_other_smbds,
1369 CONST_DISCARD(void *,
1370 client_addr(get_client_fd(),addr,sizeof(addr))));
1374 /****************************************************************************
1375 Reply to a session setup command.
1376 ****************************************************************************/
1378 void reply_sesssetup_and_X(struct smb_request *req)
1380 int sess_vuid;
1381 int smb_bufsize;
1382 DATA_BLOB lm_resp;
1383 DATA_BLOB nt_resp;
1384 DATA_BLOB plaintext_password;
1385 char *tmp;
1386 const char *user;
1387 fstring sub_user; /* Sainitised username for substituion */
1388 const char *domain;
1389 const char *native_os;
1390 const char *native_lanman;
1391 const char *primary_domain;
1392 auth_usersupplied_info *user_info = NULL;
1393 auth_serversupplied_info *server_info = NULL;
1394 uint16 smb_flag2 = req->flags2;
1396 NTSTATUS nt_status;
1397 struct smbd_server_connection *sconn = smbd_server_conn;
1399 bool doencrypt = sconn->smb1.negprot.encrypted_passwords;
1401 START_PROFILE(SMBsesssetupX);
1403 ZERO_STRUCT(lm_resp);
1404 ZERO_STRUCT(nt_resp);
1405 ZERO_STRUCT(plaintext_password);
1407 DEBUG(3,("wct=%d flg2=0x%x\n", req->wct, req->flags2));
1409 /* a SPNEGO session setup has 12 command words, whereas a normal
1410 NT1 session setup has 13. See the cifs spec. */
1411 if (req->wct == 12 &&
1412 (req->flags2 & FLAGS2_EXTENDED_SECURITY)) {
1414 if (!sconn->smb1.negprot.spnego) {
1415 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt "
1416 "at SPNEGO session setup when it was not "
1417 "negotiated.\n"));
1418 reply_nterror(req, nt_status_squash(
1419 NT_STATUS_LOGON_FAILURE));
1420 END_PROFILE(SMBsesssetupX);
1421 return;
1424 if (SVAL(req->vwv+4, 0) == 0) {
1425 setup_new_vc_session();
1428 reply_sesssetup_and_X_spnego(req);
1429 END_PROFILE(SMBsesssetupX);
1430 return;
1433 smb_bufsize = SVAL(req->vwv+2, 0);
1435 if (Protocol < PROTOCOL_NT1) {
1436 uint16 passlen1 = SVAL(req->vwv+7, 0);
1438 /* Never do NT status codes with protocols before NT1 as we
1439 * don't get client caps. */
1440 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1442 if ((passlen1 > MAX_PASS_LEN) || (passlen1 > req->buflen)) {
1443 reply_nterror(req, nt_status_squash(
1444 NT_STATUS_INVALID_PARAMETER));
1445 END_PROFILE(SMBsesssetupX);
1446 return;
1449 if (doencrypt) {
1450 lm_resp = data_blob(req->buf, passlen1);
1451 } else {
1452 plaintext_password = data_blob(req->buf, passlen1+1);
1453 /* Ensure null termination */
1454 plaintext_password.data[passlen1] = 0;
1457 srvstr_pull_req_talloc(talloc_tos(), req, &tmp,
1458 req->buf + passlen1, STR_TERMINATE);
1459 user = tmp ? tmp : "";
1461 domain = "";
1463 } else {
1464 uint16 passlen1 = SVAL(req->vwv+7, 0);
1465 uint16 passlen2 = SVAL(req->vwv+8, 0);
1466 enum remote_arch_types ra_type = get_remote_arch();
1467 const uint8_t *p = req->buf;
1468 const uint8_t *save_p = req->buf;
1469 uint16 byte_count;
1472 if(global_client_caps == 0) {
1473 global_client_caps = IVAL(req->vwv+11, 0);
1475 if (!(global_client_caps & CAP_STATUS32)) {
1476 remove_from_common_flags2(
1477 FLAGS2_32_BIT_ERROR_CODES);
1480 /* client_caps is used as final determination if
1481 * client is NT or Win95. This is needed to return
1482 * the correct error codes in some circumstances.
1485 if(ra_type == RA_WINNT || ra_type == RA_WIN2K ||
1486 ra_type == RA_WIN95) {
1487 if(!(global_client_caps & (CAP_NT_SMBS|
1488 CAP_STATUS32))) {
1489 set_remote_arch( RA_WIN95);
1494 if (!doencrypt) {
1495 /* both Win95 and WinNT stuff up the password
1496 * lengths for non-encrypting systems. Uggh.
1498 if passlen1==24 its a win95 system, and its setting
1499 the password length incorrectly. Luckily it still
1500 works with the default code because Win95 will null
1501 terminate the password anyway
1503 if passlen1>0 and passlen2>0 then maybe its a NT box
1504 and its setting passlen2 to some random value which
1505 really stuffs things up. we need to fix that one. */
1507 if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 &&
1508 passlen2 != 1) {
1509 passlen2 = 0;
1513 /* check for nasty tricks */
1514 if (passlen1 > MAX_PASS_LEN
1515 || passlen1 > smbreq_bufrem(req, p)) {
1516 reply_nterror(req, nt_status_squash(
1517 NT_STATUS_INVALID_PARAMETER));
1518 END_PROFILE(SMBsesssetupX);
1519 return;
1522 if (passlen2 > MAX_PASS_LEN
1523 || passlen2 > smbreq_bufrem(req, p+passlen1)) {
1524 reply_nterror(req, nt_status_squash(
1525 NT_STATUS_INVALID_PARAMETER));
1526 END_PROFILE(SMBsesssetupX);
1527 return;
1530 /* Save the lanman2 password and the NT md4 password. */
1532 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
1533 doencrypt = False;
1536 if (doencrypt) {
1537 lm_resp = data_blob(p, passlen1);
1538 nt_resp = data_blob(p+passlen1, passlen2);
1539 } else if (lp_security() != SEC_SHARE) {
1541 * In share level we should ignore any passwords, so
1542 * only read them if we're not.
1544 char *pass = NULL;
1545 bool unic= smb_flag2 & FLAGS2_UNICODE_STRINGS;
1547 if (unic && (passlen2 == 0) && passlen1) {
1548 /* Only a ascii plaintext password was sent. */
1549 (void)srvstr_pull_talloc(talloc_tos(),
1550 req->inbuf,
1551 req->flags2,
1552 &pass,
1553 req->buf,
1554 passlen1,
1555 STR_TERMINATE|STR_ASCII);
1556 } else {
1557 (void)srvstr_pull_talloc(talloc_tos(),
1558 req->inbuf,
1559 req->flags2,
1560 &pass,
1561 req->buf,
1562 unic ? passlen2 : passlen1,
1563 STR_TERMINATE);
1565 if (!pass) {
1566 reply_nterror(req, nt_status_squash(
1567 NT_STATUS_INVALID_PARAMETER));
1568 END_PROFILE(SMBsesssetupX);
1569 return;
1571 plaintext_password = data_blob(pass, strlen(pass)+1);
1574 p += passlen1 + passlen2;
1576 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1577 STR_TERMINATE);
1578 user = tmp ? tmp : "";
1580 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1581 STR_TERMINATE);
1582 domain = tmp ? tmp : "";
1584 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1585 STR_TERMINATE);
1586 native_os = tmp ? tmp : "";
1588 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1589 STR_TERMINATE);
1590 native_lanman = tmp ? tmp : "";
1592 /* not documented or decoded by Ethereal but there is one more
1593 * string in the extra bytes which is the same as the
1594 * PrimaryDomain when using extended security. Windows NT 4
1595 * and 2003 use this string to store the native lanman string.
1596 * Windows 9x does not include a string here at all so we have
1597 * to check if we have any extra bytes left */
1599 byte_count = SVAL(req->vwv+13, 0);
1600 if ( PTR_DIFF(p, save_p) < byte_count) {
1601 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1602 STR_TERMINATE);
1603 primary_domain = tmp ? tmp : "";
1604 } else {
1605 primary_domain = talloc_strdup(talloc_tos(), "null");
1608 DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s] "
1609 "PrimaryDomain=[%s]\n",
1610 domain, native_os, native_lanman, primary_domain));
1612 if ( ra_type == RA_WIN2K ) {
1613 if ( strlen(native_lanman) == 0 )
1614 ra_lanman_string( primary_domain );
1615 else
1616 ra_lanman_string( native_lanman );
1621 if (SVAL(req->vwv+4, 0) == 0) {
1622 setup_new_vc_session();
1625 DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n",
1626 domain, user, get_remote_machine_name()));
1628 if (*user) {
1629 if (sconn->smb1.negprot.spnego) {
1631 /* This has to be here, because this is a perfectly
1632 * valid behaviour for guest logons :-( */
1634 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt "
1635 "at 'normal' session setup after "
1636 "negotiating spnego.\n"));
1637 reply_nterror(req, nt_status_squash(
1638 NT_STATUS_LOGON_FAILURE));
1639 END_PROFILE(SMBsesssetupX);
1640 return;
1642 fstrcpy(sub_user, user);
1643 } else {
1644 fstrcpy(sub_user, lp_guestaccount());
1647 sub_set_smb_name(sub_user);
1649 reload_services(True);
1651 if (lp_security() == SEC_SHARE) {
1652 /* In share level we should ignore any passwords */
1654 data_blob_free(&lm_resp);
1655 data_blob_free(&nt_resp);
1656 data_blob_clear_free(&plaintext_password);
1658 map_username(sconn, sub_user);
1659 add_session_user(sconn, sub_user);
1660 add_session_workgroup(sconn, domain);
1661 /* Then force it to null for the benfit of the code below */
1662 user = "";
1665 if (!*user) {
1667 nt_status = check_guest_password(&server_info);
1669 } else if (doencrypt) {
1670 struct auth_context *negprot_auth_context = NULL;
1671 negprot_auth_context = sconn->smb1.negprot.auth_context;
1672 if (!negprot_auth_context) {
1673 DEBUG(0, ("reply_sesssetup_and_X: Attempted encrypted "
1674 "session setup without negprot denied!\n"));
1675 reply_nterror(req, nt_status_squash(
1676 NT_STATUS_LOGON_FAILURE));
1677 END_PROFILE(SMBsesssetupX);
1678 return;
1680 nt_status = make_user_info_for_reply_enc(&user_info, user,
1681 domain,
1682 lm_resp, nt_resp);
1683 if (NT_STATUS_IS_OK(nt_status)) {
1684 nt_status = negprot_auth_context->check_ntlm_password(
1685 negprot_auth_context,
1686 user_info,
1687 &server_info);
1689 } else {
1690 struct auth_context *plaintext_auth_context = NULL;
1692 nt_status = make_auth_context_subsystem(
1693 &plaintext_auth_context);
1695 if (NT_STATUS_IS_OK(nt_status)) {
1696 uint8_t chal[8];
1698 plaintext_auth_context->get_ntlm_challenge(
1699 plaintext_auth_context, chal);
1701 if (!make_user_info_for_reply(&user_info,
1702 user, domain, chal,
1703 plaintext_password)) {
1704 nt_status = NT_STATUS_NO_MEMORY;
1707 if (NT_STATUS_IS_OK(nt_status)) {
1708 nt_status = plaintext_auth_context->check_ntlm_password(
1709 plaintext_auth_context,
1710 user_info,
1711 &server_info);
1713 (plaintext_auth_context->free)(
1714 &plaintext_auth_context);
1719 free_user_info(&user_info);
1721 if (!NT_STATUS_IS_OK(nt_status)) {
1722 nt_status = do_map_to_guest(nt_status, &server_info,
1723 user, domain);
1726 if (!NT_STATUS_IS_OK(nt_status)) {
1727 data_blob_free(&nt_resp);
1728 data_blob_free(&lm_resp);
1729 data_blob_clear_free(&plaintext_password);
1730 reply_nterror(req, nt_status_squash(nt_status));
1731 END_PROFILE(SMBsesssetupX);
1732 return;
1735 /* Ensure we can't possible take a code path leading to a
1736 * null defref. */
1737 if (!server_info) {
1738 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1739 END_PROFILE(SMBsesssetupX);
1740 return;
1743 if (!server_info->ptok) {
1744 nt_status = create_local_token(server_info);
1746 if (!NT_STATUS_IS_OK(nt_status)) {
1747 DEBUG(10, ("create_local_token failed: %s\n",
1748 nt_errstr(nt_status)));
1749 data_blob_free(&nt_resp);
1750 data_blob_free(&lm_resp);
1751 data_blob_clear_free(&plaintext_password);
1752 reply_nterror(req, nt_status_squash(nt_status));
1753 END_PROFILE(SMBsesssetupX);
1754 return;
1758 data_blob_clear_free(&plaintext_password);
1760 /* it's ok - setup a reply */
1761 reply_outbuf(req, 3, 0);
1762 if (Protocol >= PROTOCOL_NT1) {
1763 push_signature(&req->outbuf);
1764 /* perhaps grab OS version here?? */
1767 if (server_info->guest) {
1768 SSVAL(req->outbuf,smb_vwv2,1);
1771 /* register the name and uid as being validated, so further connections
1772 to a uid can get through without a password, on the same VC */
1774 if (lp_security() == SEC_SHARE) {
1775 sess_vuid = UID_FIELD_INVALID;
1776 TALLOC_FREE(server_info);
1777 } else {
1778 /* Ignore the initial vuid. */
1779 sess_vuid = register_initial_vuid(sconn);
1780 if (sess_vuid == UID_FIELD_INVALID) {
1781 data_blob_free(&nt_resp);
1782 data_blob_free(&lm_resp);
1783 reply_nterror(req, nt_status_squash(
1784 NT_STATUS_LOGON_FAILURE));
1785 END_PROFILE(SMBsesssetupX);
1786 return;
1788 /* register_existing_vuid keeps the server info */
1789 sess_vuid = register_existing_vuid(sconn, sess_vuid,
1790 server_info,
1791 nt_resp.data ? nt_resp : lm_resp,
1792 sub_user);
1793 if (sess_vuid == UID_FIELD_INVALID) {
1794 data_blob_free(&nt_resp);
1795 data_blob_free(&lm_resp);
1796 reply_nterror(req, nt_status_squash(
1797 NT_STATUS_LOGON_FAILURE));
1798 END_PROFILE(SMBsesssetupX);
1799 return;
1802 /* current_user_info is changed on new vuid */
1803 reload_services( True );
1806 data_blob_free(&nt_resp);
1807 data_blob_free(&lm_resp);
1809 SSVAL(req->outbuf,smb_uid,sess_vuid);
1810 SSVAL(req->inbuf,smb_uid,sess_vuid);
1811 req->vuid = sess_vuid;
1813 if (!sconn->smb1.sessions.done_sesssetup) {
1814 sconn->smb1.sessions.max_send =
1815 MIN(sconn->smb1.sessions.max_send,smb_bufsize);
1817 sconn->smb1.sessions.done_sesssetup = true;
1819 END_PROFILE(SMBsesssetupX);
1820 chain_reply(req);
1821 return;