s3:configure: use correct SONAMEFLAG on Solaris depending on which linker is being...
[Samba.git] / source3 / smbd / sesssetup.c
bloba00a362537c073e7ca46005cabb136e8949d71a0
1 /*
2 Unix SMB/CIFS implementation.
3 handle SMBsessionsetup
4 Copyright (C) Andrew Tridgell 1998-2001
5 Copyright (C) Andrew Bartlett 2001
6 Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002
7 Copyright (C) Luke Howard 2003
8 Copyright (C) Volker Lendecke 2007
9 Copyright (C) Jeremy Allison 2007
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 3 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "includes.h"
26 #include "smbd/globals.h"
27 #include "../libcli/auth/spnego.h"
28 #include "ntlmssp.h"
29 #include "librpc/gen_ndr/messaging.h"
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 struct 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(struct auth_serversupplied_info **server_info)
134 struct auth_context *auth_context;
135 struct 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 struct 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 {
491 * We didn't get a PAC, we have to make up the user
492 * ourselves. Try to ask the pdb backend to provide
493 * SID consistency with ntlmssp session setup
495 struct samu *sampass;
497 sampass = samu_new(talloc_tos());
498 if (sampass == NULL) {
499 ret = NT_STATUS_NO_MEMORY;
500 data_blob_free(&ap_rep);
501 data_blob_free(&session_key);
502 TALLOC_FREE(mem_ctx);
503 reply_nterror(req, nt_status_squash(ret));
504 return;
507 if (pdb_getsampwnam(sampass, real_username)) {
508 DEBUG(10, ("found user %s in passdb, calling "
509 "make_server_info_sam\n", real_username));
510 ret = make_server_info_sam(&server_info, sampass);
511 } else {
513 * User not in passdb, make it up artificially
515 TALLOC_FREE(sampass);
516 DEBUG(10, ("didn't find user %s in passdb, calling "
517 "make_server_info_pw\n", real_username));
518 ret = make_server_info_pw(&server_info, real_username,
519 pw);
522 if ( !NT_STATUS_IS_OK(ret) ) {
523 DEBUG(1,("make_server_info_[sam|pw] failed: %s!\n",
524 nt_errstr(ret)));
525 data_blob_free(&ap_rep);
526 data_blob_free(&session_key);
527 TALLOC_FREE(mem_ctx);
528 reply_nterror(req, nt_status_squash(ret));
529 return;
532 /* make_server_info_pw does not set the domain. Without this
533 * we end up with the local netbios name in substitutions for
534 * %D. */
536 if (server_info->sam_account != NULL) {
537 pdb_set_domain(server_info->sam_account,
538 domain, PDB_SET);
542 server_info->nss_token |= username_was_mapped;
544 /* we need to build the token for the user. make_server_info_guest()
545 already does this */
547 if ( !server_info->ptok ) {
548 ret = create_local_token( server_info );
549 if ( !NT_STATUS_IS_OK(ret) ) {
550 DEBUG(10,("failed to create local token: %s\n",
551 nt_errstr(ret)));
552 data_blob_free(&ap_rep);
553 data_blob_free(&session_key);
554 TALLOC_FREE( mem_ctx );
555 TALLOC_FREE( server_info );
556 reply_nterror(req, nt_status_squash(ret));
557 return;
561 if (!is_partial_auth_vuid(sconn, sess_vuid)) {
562 sess_vuid = register_initial_vuid(sconn);
565 data_blob_free(&server_info->user_session_key);
566 server_info->user_session_key = session_key;
567 session_key = data_blob_null;
569 /* register_existing_vuid keeps the server info */
570 /* register_existing_vuid takes ownership of session_key on success,
571 * no need to free after this on success. A better interface would copy
572 * it.... */
574 sess_vuid = register_existing_vuid(sconn,
575 sess_vuid,
576 server_info,
577 nullblob,
578 client);
580 reply_outbuf(req, 4, 0);
581 SSVAL(req->outbuf,smb_uid,sess_vuid);
583 if (sess_vuid == UID_FIELD_INVALID ) {
584 ret = NT_STATUS_LOGON_FAILURE;
585 } else {
586 /* current_user_info is changed on new vuid */
587 reload_services( True );
589 SSVAL(req->outbuf, smb_vwv3, 0);
591 if (server_info->guest) {
592 SSVAL(req->outbuf,smb_vwv2,1);
595 SSVAL(req->outbuf, smb_uid, sess_vuid);
597 /* Successful logon. Keep this vuid. */
598 *p_invalidate_vuid = False;
601 /* wrap that up in a nice GSS-API wrapping */
602 if (NT_STATUS_IS_OK(ret)) {
603 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep,
604 TOK_ID_KRB_AP_REP);
605 } else {
606 ap_rep_wrapped = data_blob_null;
608 response = spnego_gen_auth_response(&ap_rep_wrapped, ret,
609 mechOID);
610 reply_sesssetup_blob(req, response, ret);
612 data_blob_free(&ap_rep);
613 data_blob_free(&ap_rep_wrapped);
614 data_blob_free(&response);
615 TALLOC_FREE(mem_ctx);
618 #endif
620 /****************************************************************************
621 Send a session setup reply, wrapped in SPNEGO.
622 Get vuid and check first.
623 End the NTLMSSP exchange context if we are OK/complete fail
624 This should be split into two functions, one to handle each
625 leg of the NTLM auth steps.
626 ***************************************************************************/
628 static void reply_spnego_ntlmssp(struct smb_request *req,
629 uint16 vuid,
630 AUTH_NTLMSSP_STATE **auth_ntlmssp_state,
631 DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status,
632 const char *OID,
633 bool wrap)
635 DATA_BLOB response;
636 struct auth_serversupplied_info *server_info = NULL;
637 struct smbd_server_connection *sconn = smbd_server_conn;
639 if (NT_STATUS_IS_OK(nt_status)) {
640 server_info = (*auth_ntlmssp_state)->server_info;
641 } else {
642 nt_status = do_map_to_guest(nt_status,
643 &server_info,
644 (*auth_ntlmssp_state)->ntlmssp_state->user,
645 (*auth_ntlmssp_state)->ntlmssp_state->domain);
648 reply_outbuf(req, 4, 0);
650 SSVAL(req->outbuf, smb_uid, vuid);
652 if (NT_STATUS_IS_OK(nt_status)) {
653 DATA_BLOB nullblob = data_blob_null;
655 if (!is_partial_auth_vuid(sconn, vuid)) {
656 nt_status = NT_STATUS_LOGON_FAILURE;
657 goto out;
660 data_blob_free(&server_info->user_session_key);
661 server_info->user_session_key =
662 data_blob_talloc(
663 server_info,
664 (*auth_ntlmssp_state)->ntlmssp_state->session_key.data,
665 (*auth_ntlmssp_state)->ntlmssp_state->session_key.length);
667 /* register_existing_vuid keeps the server info */
668 if (register_existing_vuid(sconn, vuid,
669 server_info, nullblob,
670 (*auth_ntlmssp_state)->ntlmssp_state->user) !=
671 vuid) {
672 nt_status = NT_STATUS_LOGON_FAILURE;
673 goto out;
676 (*auth_ntlmssp_state)->server_info = NULL;
678 /* current_user_info is changed on new vuid */
679 reload_services( True );
681 SSVAL(req->outbuf, smb_vwv3, 0);
683 if (server_info->guest) {
684 SSVAL(req->outbuf,smb_vwv2,1);
688 out:
690 if (wrap) {
691 response = spnego_gen_auth_response(ntlmssp_blob,
692 nt_status, OID);
693 } else {
694 response = *ntlmssp_blob;
697 reply_sesssetup_blob(req, response, nt_status);
698 if (wrap) {
699 data_blob_free(&response);
702 /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
703 and the other end, that we are not finished yet. */
705 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
706 /* NB. This is *NOT* an error case. JRA */
707 auth_ntlmssp_end(auth_ntlmssp_state);
708 if (!NT_STATUS_IS_OK(nt_status)) {
709 /* Kill the intermediate vuid */
710 invalidate_vuid(sconn, vuid);
715 /****************************************************************************
716 Is this a krb5 mechanism ?
717 ****************************************************************************/
719 NTSTATUS parse_spnego_mechanisms(DATA_BLOB blob_in,
720 DATA_BLOB *pblob_out,
721 char **kerb_mechOID)
723 char *OIDs[ASN1_MAX_OIDS];
724 int i;
725 NTSTATUS ret = NT_STATUS_OK;
727 *kerb_mechOID = NULL;
729 /* parse out the OIDs and the first sec blob */
730 if (!parse_negTokenTarg(blob_in, OIDs, pblob_out)) {
731 return NT_STATUS_LOGON_FAILURE;
734 /* only look at the first OID for determining the mechToken --
735 according to RFC2478, we should choose the one we want
736 and renegotiate, but i smell a client bug here..
738 Problem observed when connecting to a member (samba box)
739 of an AD domain as a user in a Samba domain. Samba member
740 server sent back krb5/mskrb5/ntlmssp as mechtypes, but the
741 client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an
742 NTLMSSP mechtoken. --jerry */
744 #ifdef HAVE_KRB5
745 if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||
746 strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
747 *kerb_mechOID = SMB_STRDUP(OIDs[0]);
748 if (*kerb_mechOID == NULL) {
749 ret = NT_STATUS_NO_MEMORY;
752 #endif
754 for (i=0;OIDs[i];i++) {
755 DEBUG(5,("parse_spnego_mechanisms: Got OID %s\n", OIDs[i]));
756 talloc_free(OIDs[i]);
758 return ret;
761 /****************************************************************************
762 Fall back from krb5 to NTLMSSP.
763 ****************************************************************************/
765 static void reply_spnego_downgrade_to_ntlmssp(struct smb_request *req,
766 uint16 vuid)
768 DATA_BLOB response;
770 reply_outbuf(req, 4, 0);
771 SSVAL(req->outbuf,smb_uid,vuid);
773 DEBUG(3,("reply_spnego_downgrade_to_ntlmssp: Got krb5 ticket in SPNEGO "
774 "but set to downgrade to NTLMSSP\n"));
776 response = spnego_gen_auth_response(NULL,
777 NT_STATUS_MORE_PROCESSING_REQUIRED,
778 OID_NTLMSSP);
779 reply_sesssetup_blob(req, response, NT_STATUS_MORE_PROCESSING_REQUIRED);
780 data_blob_free(&response);
783 /****************************************************************************
784 Reply to a session setup spnego negotiate packet.
785 ****************************************************************************/
787 static void reply_spnego_negotiate(struct smb_request *req,
788 uint16 vuid,
789 DATA_BLOB blob1,
790 AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
792 DATA_BLOB secblob;
793 DATA_BLOB chal;
794 char *kerb_mech = NULL;
795 NTSTATUS status;
796 struct smbd_server_connection *sconn = smbd_server_conn;
798 status = parse_spnego_mechanisms(blob1, &secblob, &kerb_mech);
799 if (!NT_STATUS_IS_OK(status)) {
800 /* Kill the intermediate vuid */
801 invalidate_vuid(sconn, vuid);
802 reply_nterror(req, nt_status_squash(status));
803 return;
806 DEBUG(3,("reply_spnego_negotiate: Got secblob of size %lu\n",
807 (unsigned long)secblob.length));
809 #ifdef HAVE_KRB5
810 if (kerb_mech && ((lp_security()==SEC_ADS) ||
811 USE_KERBEROS_KEYTAB) ) {
812 bool destroy_vuid = True;
813 reply_spnego_kerberos(req, &secblob, kerb_mech,
814 vuid, &destroy_vuid);
815 data_blob_free(&secblob);
816 if (destroy_vuid) {
817 /* Kill the intermediate vuid */
818 invalidate_vuid(sconn, vuid);
820 SAFE_FREE(kerb_mech);
821 return;
823 #endif
825 if (*auth_ntlmssp_state) {
826 auth_ntlmssp_end(auth_ntlmssp_state);
829 if (kerb_mech) {
830 data_blob_free(&secblob);
831 /* The mechtoken is a krb5 ticket, but
832 * we need to fall back to NTLM. */
833 reply_spnego_downgrade_to_ntlmssp(req, vuid);
834 SAFE_FREE(kerb_mech);
835 return;
838 status = auth_ntlmssp_start(auth_ntlmssp_state);
839 if (!NT_STATUS_IS_OK(status)) {
840 /* Kill the intermediate vuid */
841 invalidate_vuid(sconn, vuid);
842 reply_nterror(req, nt_status_squash(status));
843 return;
846 status = auth_ntlmssp_update(*auth_ntlmssp_state,
847 secblob, &chal);
849 data_blob_free(&secblob);
851 reply_spnego_ntlmssp(req, vuid, auth_ntlmssp_state,
852 &chal, status, OID_NTLMSSP, true);
854 data_blob_free(&chal);
856 /* already replied */
857 return;
860 /****************************************************************************
861 Reply to a session setup spnego auth packet.
862 ****************************************************************************/
864 static void reply_spnego_auth(struct smb_request *req,
865 uint16 vuid,
866 DATA_BLOB blob1,
867 AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
869 DATA_BLOB auth = data_blob_null;
870 DATA_BLOB auth_reply = data_blob_null;
871 DATA_BLOB secblob = data_blob_null;
872 NTSTATUS status = NT_STATUS_LOGON_FAILURE;
873 struct smbd_server_connection *sconn = smbd_server_conn;
875 if (!spnego_parse_auth(blob1, &auth)) {
876 #if 0
877 file_save("auth.dat", blob1.data, blob1.length);
878 #endif
879 /* Kill the intermediate vuid */
880 invalidate_vuid(sconn, vuid);
882 reply_nterror(req, nt_status_squash(
883 NT_STATUS_LOGON_FAILURE));
884 return;
887 if (auth.data[0] == ASN1_APPLICATION(0)) {
888 /* Might be a second negTokenTarg packet */
889 char *kerb_mech = NULL;
891 status = parse_spnego_mechanisms(auth, &secblob, &kerb_mech);
893 if (!NT_STATUS_IS_OK(status)) {
894 /* Kill the intermediate vuid */
895 invalidate_vuid(sconn, vuid);
896 reply_nterror(req, nt_status_squash(status));
897 return;
900 DEBUG(3,("reply_spnego_auth: Got secblob of size %lu\n",
901 (unsigned long)secblob.length));
902 #ifdef HAVE_KRB5
903 if (kerb_mech && ((lp_security()==SEC_ADS) ||
904 USE_KERBEROS_KEYTAB)) {
905 bool destroy_vuid = True;
906 reply_spnego_kerberos(req, &secblob, kerb_mech,
907 vuid, &destroy_vuid);
908 data_blob_free(&secblob);
909 data_blob_free(&auth);
910 if (destroy_vuid) {
911 /* Kill the intermediate vuid */
912 invalidate_vuid(sconn, vuid);
914 SAFE_FREE(kerb_mech);
915 return;
917 #endif
918 /* Can't blunder into NTLMSSP auth if we have
919 * a krb5 ticket. */
921 if (kerb_mech) {
922 /* Kill the intermediate vuid */
923 invalidate_vuid(sconn, vuid);
924 DEBUG(3,("reply_spnego_auth: network "
925 "misconfiguration, client sent us a "
926 "krb5 ticket and kerberos security "
927 "not enabled\n"));
928 reply_nterror(req, nt_status_squash(
929 NT_STATUS_LOGON_FAILURE));
930 SAFE_FREE(kerb_mech);
934 /* If we get here it wasn't a negTokenTarg auth packet. */
935 data_blob_free(&secblob);
937 if (!*auth_ntlmssp_state) {
938 status = auth_ntlmssp_start(auth_ntlmssp_state);
939 if (!NT_STATUS_IS_OK(status)) {
940 /* Kill the intermediate vuid */
941 invalidate_vuid(sconn, vuid);
942 reply_nterror(req, nt_status_squash(status));
943 return;
947 status = auth_ntlmssp_update(*auth_ntlmssp_state,
948 auth, &auth_reply);
950 data_blob_free(&auth);
952 /* Don't send the mechid as we've already sent this (RFC4178). */
954 reply_spnego_ntlmssp(req, vuid,
955 auth_ntlmssp_state,
956 &auth_reply, status, NULL, true);
958 data_blob_free(&auth_reply);
960 /* and tell smbd that we have already replied to this packet */
961 return;
964 /****************************************************************************
965 Delete an entry on the list.
966 ****************************************************************************/
968 static void delete_partial_auth(struct smbd_server_connection *sconn,
969 struct pending_auth_data *pad)
971 if (!pad) {
972 return;
974 DLIST_REMOVE(sconn->smb1.pd_list, pad);
975 data_blob_free(&pad->partial_data);
976 SAFE_FREE(pad);
979 /****************************************************************************
980 Search for a partial SPNEGO auth fragment matching an smbpid.
981 ****************************************************************************/
983 static struct pending_auth_data *get_pending_auth_data(
984 struct smbd_server_connection *sconn,
985 uint16_t smbpid)
987 struct pending_auth_data *pad;
989 * NOTE: using the smbpid here is completely wrong...
990 * see [MS-SMB]
991 * 3.3.5.3 Receiving an SMB_COM_SESSION_SETUP_ANDX Request
993 for (pad = sconn->smb1.pd_list; pad; pad = pad->next) {
994 if (pad->smbpid == smbpid) {
995 break;
998 return pad;
1001 /****************************************************************************
1002 Check the size of an SPNEGO blob. If we need more return
1003 NT_STATUS_MORE_PROCESSING_REQUIRED, else return NT_STATUS_OK. Don't allow
1004 the blob to be more than 64k.
1005 ****************************************************************************/
1007 static NTSTATUS check_spnego_blob_complete(struct smbd_server_connection *sconn,
1008 uint16 smbpid, uint16 vuid,
1009 DATA_BLOB *pblob)
1011 struct pending_auth_data *pad = NULL;
1012 ASN1_DATA *data;
1013 size_t needed_len = 0;
1015 pad = get_pending_auth_data(sconn, smbpid);
1017 /* Ensure we have some data. */
1018 if (pblob->length == 0) {
1019 /* Caller can cope. */
1020 DEBUG(2,("check_spnego_blob_complete: zero blob length !\n"));
1021 delete_partial_auth(sconn, pad);
1022 return NT_STATUS_OK;
1025 /* Were we waiting for more data ? */
1026 if (pad) {
1027 DATA_BLOB tmp_blob;
1028 size_t copy_len = MIN(65536, pblob->length);
1030 /* Integer wrap paranoia.... */
1032 if (pad->partial_data.length + copy_len <
1033 pad->partial_data.length ||
1034 pad->partial_data.length + copy_len < copy_len) {
1036 DEBUG(2,("check_spnego_blob_complete: integer wrap "
1037 "pad->partial_data.length = %u, "
1038 "copy_len = %u\n",
1039 (unsigned int)pad->partial_data.length,
1040 (unsigned int)copy_len ));
1042 delete_partial_auth(sconn, pad);
1043 return NT_STATUS_INVALID_PARAMETER;
1046 DEBUG(10,("check_spnego_blob_complete: "
1047 "pad->partial_data.length = %u, "
1048 "pad->needed_len = %u, "
1049 "copy_len = %u, "
1050 "pblob->length = %u,\n",
1051 (unsigned int)pad->partial_data.length,
1052 (unsigned int)pad->needed_len,
1053 (unsigned int)copy_len,
1054 (unsigned int)pblob->length ));
1056 tmp_blob = data_blob(NULL,
1057 pad->partial_data.length + copy_len);
1059 /* Concatenate the two (up to copy_len) bytes. */
1060 memcpy(tmp_blob.data,
1061 pad->partial_data.data,
1062 pad->partial_data.length);
1063 memcpy(tmp_blob.data + pad->partial_data.length,
1064 pblob->data,
1065 copy_len);
1067 /* Replace the partial data. */
1068 data_blob_free(&pad->partial_data);
1069 pad->partial_data = tmp_blob;
1070 ZERO_STRUCT(tmp_blob);
1072 /* Are we done ? */
1073 if (pblob->length >= pad->needed_len) {
1074 /* Yes, replace pblob. */
1075 data_blob_free(pblob);
1076 *pblob = pad->partial_data;
1077 ZERO_STRUCT(pad->partial_data);
1078 delete_partial_auth(sconn, pad);
1079 return NT_STATUS_OK;
1082 /* Still need more data. */
1083 pad->needed_len -= copy_len;
1084 return NT_STATUS_MORE_PROCESSING_REQUIRED;
1087 if ((pblob->data[0] != ASN1_APPLICATION(0)) &&
1088 (pblob->data[0] != ASN1_CONTEXT(1))) {
1089 /* Not something we can determine the
1090 * length of.
1092 return NT_STATUS_OK;
1095 /* This is a new SPNEGO sessionsetup - see if
1096 * the data given in this blob is enough.
1099 data = asn1_init(NULL);
1100 if (data == NULL) {
1101 return NT_STATUS_NO_MEMORY;
1104 asn1_load(data, *pblob);
1105 asn1_start_tag(data, pblob->data[0]);
1106 if (data->has_error || data->nesting == NULL) {
1107 asn1_free(data);
1108 /* Let caller catch. */
1109 return NT_STATUS_OK;
1112 /* Integer wrap paranoia.... */
1114 if (data->nesting->taglen + data->nesting->start < data->nesting->taglen ||
1115 data->nesting->taglen + data->nesting->start < data->nesting->start) {
1117 DEBUG(2,("check_spnego_blob_complete: integer wrap "
1118 "data.nesting->taglen = %u, "
1119 "data.nesting->start = %u\n",
1120 (unsigned int)data->nesting->taglen,
1121 (unsigned int)data->nesting->start ));
1123 asn1_free(data);
1124 return NT_STATUS_INVALID_PARAMETER;
1127 /* Total length of the needed asn1 is the tag length
1128 * plus the current offset. */
1130 needed_len = data->nesting->taglen + data->nesting->start;
1131 asn1_free(data);
1133 DEBUG(10,("check_spnego_blob_complete: needed_len = %u, "
1134 "pblob->length = %u\n",
1135 (unsigned int)needed_len,
1136 (unsigned int)pblob->length ));
1138 if (needed_len <= pblob->length) {
1139 /* Nothing to do - blob is complete. */
1140 return NT_STATUS_OK;
1143 /* Refuse the blob if it's bigger than 64k. */
1144 if (needed_len > 65536) {
1145 DEBUG(2,("check_spnego_blob_complete: needed_len "
1146 "too large (%u)\n",
1147 (unsigned int)needed_len ));
1148 return NT_STATUS_INVALID_PARAMETER;
1151 /* We must store this blob until complete. */
1152 if (!(pad = SMB_MALLOC_P(struct pending_auth_data))) {
1153 return NT_STATUS_NO_MEMORY;
1155 pad->needed_len = needed_len - pblob->length;
1156 pad->partial_data = data_blob(pblob->data, pblob->length);
1157 if (pad->partial_data.data == NULL) {
1158 SAFE_FREE(pad);
1159 return NT_STATUS_NO_MEMORY;
1161 pad->smbpid = smbpid;
1162 pad->vuid = vuid;
1163 DLIST_ADD(sconn->smb1.pd_list, pad);
1165 return NT_STATUS_MORE_PROCESSING_REQUIRED;
1168 /****************************************************************************
1169 Reply to a session setup command.
1170 conn POINTER CAN BE NULL HERE !
1171 ****************************************************************************/
1173 static void reply_sesssetup_and_X_spnego(struct smb_request *req)
1175 const uint8 *p;
1176 DATA_BLOB blob1;
1177 size_t bufrem;
1178 char *tmp;
1179 const char *native_os;
1180 const char *native_lanman;
1181 const char *primary_domain;
1182 const char *p2;
1183 uint16 data_blob_len = SVAL(req->vwv+7, 0);
1184 enum remote_arch_types ra_type = get_remote_arch();
1185 int vuid = req->vuid;
1186 user_struct *vuser = NULL;
1187 NTSTATUS status = NT_STATUS_OK;
1188 uint16 smbpid = req->smbpid;
1189 struct smbd_server_connection *sconn = smbd_server_conn;
1191 DEBUG(3,("Doing spnego session setup\n"));
1193 if (global_client_caps == 0) {
1194 global_client_caps = IVAL(req->vwv+10, 0);
1196 if (!(global_client_caps & CAP_STATUS32)) {
1197 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1202 p = req->buf;
1204 if (data_blob_len == 0) {
1205 /* an invalid request */
1206 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1207 return;
1210 bufrem = smbreq_bufrem(req, p);
1211 /* pull the spnego blob */
1212 blob1 = data_blob(p, MIN(bufrem, data_blob_len));
1214 #if 0
1215 file_save("negotiate.dat", blob1.data, blob1.length);
1216 #endif
1218 p2 = (char *)req->buf + blob1.length;
1220 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1221 STR_TERMINATE);
1222 native_os = tmp ? tmp : "";
1224 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1225 STR_TERMINATE);
1226 native_lanman = tmp ? tmp : "";
1228 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1229 STR_TERMINATE);
1230 primary_domain = tmp ? tmp : "";
1232 DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
1233 native_os, native_lanman, primary_domain));
1235 if ( ra_type == RA_WIN2K ) {
1236 /* Vista sets neither the OS or lanman strings */
1238 if ( !strlen(native_os) && !strlen(native_lanman) )
1239 set_remote_arch(RA_VISTA);
1241 /* Windows 2003 doesn't set the native lanman string,
1242 but does set primary domain which is a bug I think */
1244 if ( !strlen(native_lanman) ) {
1245 ra_lanman_string( primary_domain );
1246 } else {
1247 ra_lanman_string( native_lanman );
1251 /* Did we get a valid vuid ? */
1252 if (!is_partial_auth_vuid(sconn, vuid)) {
1253 /* No, then try and see if this is an intermediate sessionsetup
1254 * for a large SPNEGO packet. */
1255 struct pending_auth_data *pad;
1256 pad = get_pending_auth_data(sconn, smbpid);
1257 if (pad) {
1258 DEBUG(10,("reply_sesssetup_and_X_spnego: found "
1259 "pending vuid %u\n",
1260 (unsigned int)pad->vuid ));
1261 vuid = pad->vuid;
1265 /* Do we have a valid vuid now ? */
1266 if (!is_partial_auth_vuid(sconn, vuid)) {
1267 /* No, start a new authentication setup. */
1268 vuid = register_initial_vuid(sconn);
1269 if (vuid == UID_FIELD_INVALID) {
1270 data_blob_free(&blob1);
1271 reply_nterror(req, nt_status_squash(
1272 NT_STATUS_INVALID_PARAMETER));
1273 return;
1277 vuser = get_partial_auth_user_struct(sconn, vuid);
1278 /* This MUST be valid. */
1279 if (!vuser) {
1280 smb_panic("reply_sesssetup_and_X_spnego: invalid vuid.");
1283 /* Large (greater than 4k) SPNEGO blobs are split into multiple
1284 * sessionsetup requests as the Windows limit on the security blob
1285 * field is 4k. Bug #4400. JRA.
1288 status = check_spnego_blob_complete(sconn, smbpid, vuid, &blob1);
1289 if (!NT_STATUS_IS_OK(status)) {
1290 if (!NT_STATUS_EQUAL(status,
1291 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1292 /* Real error - kill the intermediate vuid */
1293 invalidate_vuid(sconn, vuid);
1295 data_blob_free(&blob1);
1296 reply_nterror(req, nt_status_squash(status));
1297 return;
1300 if (blob1.data[0] == ASN1_APPLICATION(0)) {
1302 /* its a negTokenTarg packet */
1304 reply_spnego_negotiate(req, vuid, blob1,
1305 &vuser->auth_ntlmssp_state);
1306 data_blob_free(&blob1);
1307 return;
1310 if (blob1.data[0] == ASN1_CONTEXT(1)) {
1312 /* its a auth packet */
1314 reply_spnego_auth(req, vuid, blob1,
1315 &vuser->auth_ntlmssp_state);
1316 data_blob_free(&blob1);
1317 return;
1320 if (strncmp((char *)(blob1.data), "NTLMSSP", 7) == 0) {
1321 DATA_BLOB chal;
1323 if (!vuser->auth_ntlmssp_state) {
1324 status = auth_ntlmssp_start(&vuser->auth_ntlmssp_state);
1325 if (!NT_STATUS_IS_OK(status)) {
1326 /* Kill the intermediate vuid */
1327 invalidate_vuid(sconn, vuid);
1328 data_blob_free(&blob1);
1329 reply_nterror(req, nt_status_squash(status));
1330 return;
1334 status = auth_ntlmssp_update(vuser->auth_ntlmssp_state,
1335 blob1, &chal);
1337 data_blob_free(&blob1);
1339 reply_spnego_ntlmssp(req, vuid,
1340 &vuser->auth_ntlmssp_state,
1341 &chal, status, OID_NTLMSSP, false);
1342 data_blob_free(&chal);
1343 return;
1346 /* what sort of packet is this? */
1347 DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
1349 data_blob_free(&blob1);
1351 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1354 /****************************************************************************
1355 On new VC == 0, shutdown *all* old connections and users.
1356 It seems that only NT4.x does this. At W2K and above (XP etc.).
1357 a new session setup with VC==0 is ignored.
1358 ****************************************************************************/
1360 static int shutdown_other_smbds(const struct connections_key *key,
1361 const struct connections_data *crec,
1362 void *private_data)
1364 const char *ip = (const char *)private_data;
1366 if (!process_exists(crec->pid)) {
1367 return 0;
1370 if (procid_is_me(&crec->pid)) {
1371 return 0;
1374 if (strcmp(ip, crec->addr) != 0) {
1375 return 0;
1378 DEBUG(0,("shutdown_other_smbds: shutting down pid %u "
1379 "(IP %s)\n", (unsigned int)procid_to_pid(&crec->pid), ip));
1381 messaging_send(smbd_messaging_context(), crec->pid, MSG_SHUTDOWN,
1382 &data_blob_null);
1383 return 0;
1386 static void setup_new_vc_session(void)
1388 char addr[INET6_ADDRSTRLEN];
1390 DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x "
1391 "compatible we would close all old resources.\n"));
1392 #if 0
1393 conn_close_all();
1394 invalidate_all_vuids();
1395 #endif
1396 if (lp_reset_on_zero_vc()) {
1397 connections_forall_read(shutdown_other_smbds,
1398 CONST_DISCARD(void *,
1399 client_addr(get_client_fd(),addr,sizeof(addr))));
1403 /****************************************************************************
1404 Reply to a session setup command.
1405 ****************************************************************************/
1407 void reply_sesssetup_and_X(struct smb_request *req)
1409 int sess_vuid;
1410 int smb_bufsize;
1411 DATA_BLOB lm_resp;
1412 DATA_BLOB nt_resp;
1413 DATA_BLOB plaintext_password;
1414 char *tmp;
1415 const char *user;
1416 fstring sub_user; /* Sainitised username for substituion */
1417 const char *domain;
1418 const char *native_os;
1419 const char *native_lanman;
1420 const char *primary_domain;
1421 struct auth_usersupplied_info *user_info = NULL;
1422 struct auth_serversupplied_info *server_info = NULL;
1423 uint16 smb_flag2 = req->flags2;
1425 NTSTATUS nt_status;
1426 struct smbd_server_connection *sconn = smbd_server_conn;
1428 bool doencrypt = sconn->smb1.negprot.encrypted_passwords;
1430 START_PROFILE(SMBsesssetupX);
1432 ZERO_STRUCT(lm_resp);
1433 ZERO_STRUCT(nt_resp);
1434 ZERO_STRUCT(plaintext_password);
1436 DEBUG(3,("wct=%d flg2=0x%x\n", req->wct, req->flags2));
1438 /* a SPNEGO session setup has 12 command words, whereas a normal
1439 NT1 session setup has 13. See the cifs spec. */
1440 if (req->wct == 12 &&
1441 (req->flags2 & FLAGS2_EXTENDED_SECURITY)) {
1443 if (!sconn->smb1.negprot.spnego) {
1444 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt "
1445 "at SPNEGO session setup when it was not "
1446 "negotiated.\n"));
1447 reply_nterror(req, nt_status_squash(
1448 NT_STATUS_LOGON_FAILURE));
1449 END_PROFILE(SMBsesssetupX);
1450 return;
1453 if (SVAL(req->vwv+4, 0) == 0) {
1454 setup_new_vc_session();
1457 reply_sesssetup_and_X_spnego(req);
1458 END_PROFILE(SMBsesssetupX);
1459 return;
1462 smb_bufsize = SVAL(req->vwv+2, 0);
1464 if (get_Protocol() < PROTOCOL_NT1) {
1465 uint16 passlen1 = SVAL(req->vwv+7, 0);
1467 /* Never do NT status codes with protocols before NT1 as we
1468 * don't get client caps. */
1469 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1471 if ((passlen1 > MAX_PASS_LEN) || (passlen1 > req->buflen)) {
1472 reply_nterror(req, nt_status_squash(
1473 NT_STATUS_INVALID_PARAMETER));
1474 END_PROFILE(SMBsesssetupX);
1475 return;
1478 if (doencrypt) {
1479 lm_resp = data_blob(req->buf, passlen1);
1480 } else {
1481 plaintext_password = data_blob(req->buf, passlen1+1);
1482 /* Ensure null termination */
1483 plaintext_password.data[passlen1] = 0;
1486 srvstr_pull_req_talloc(talloc_tos(), req, &tmp,
1487 req->buf + passlen1, STR_TERMINATE);
1488 user = tmp ? tmp : "";
1490 domain = "";
1492 } else {
1493 uint16 passlen1 = SVAL(req->vwv+7, 0);
1494 uint16 passlen2 = SVAL(req->vwv+8, 0);
1495 enum remote_arch_types ra_type = get_remote_arch();
1496 const uint8_t *p = req->buf;
1497 const uint8_t *save_p = req->buf;
1498 uint16 byte_count;
1501 if(global_client_caps == 0) {
1502 global_client_caps = IVAL(req->vwv+11, 0);
1504 if (!(global_client_caps & CAP_STATUS32)) {
1505 remove_from_common_flags2(
1506 FLAGS2_32_BIT_ERROR_CODES);
1509 /* client_caps is used as final determination if
1510 * client is NT or Win95. This is needed to return
1511 * the correct error codes in some circumstances.
1514 if(ra_type == RA_WINNT || ra_type == RA_WIN2K ||
1515 ra_type == RA_WIN95) {
1516 if(!(global_client_caps & (CAP_NT_SMBS|
1517 CAP_STATUS32))) {
1518 set_remote_arch( RA_WIN95);
1523 if (!doencrypt) {
1524 /* both Win95 and WinNT stuff up the password
1525 * lengths for non-encrypting systems. Uggh.
1527 if passlen1==24 its a win95 system, and its setting
1528 the password length incorrectly. Luckily it still
1529 works with the default code because Win95 will null
1530 terminate the password anyway
1532 if passlen1>0 and passlen2>0 then maybe its a NT box
1533 and its setting passlen2 to some random value which
1534 really stuffs things up. we need to fix that one. */
1536 if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 &&
1537 passlen2 != 1) {
1538 passlen2 = 0;
1542 /* check for nasty tricks */
1543 if (passlen1 > MAX_PASS_LEN
1544 || passlen1 > smbreq_bufrem(req, p)) {
1545 reply_nterror(req, nt_status_squash(
1546 NT_STATUS_INVALID_PARAMETER));
1547 END_PROFILE(SMBsesssetupX);
1548 return;
1551 if (passlen2 > MAX_PASS_LEN
1552 || passlen2 > smbreq_bufrem(req, p+passlen1)) {
1553 reply_nterror(req, nt_status_squash(
1554 NT_STATUS_INVALID_PARAMETER));
1555 END_PROFILE(SMBsesssetupX);
1556 return;
1559 /* Save the lanman2 password and the NT md4 password. */
1561 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
1562 doencrypt = False;
1565 if (doencrypt) {
1566 lm_resp = data_blob(p, passlen1);
1567 nt_resp = data_blob(p+passlen1, passlen2);
1568 } else if (lp_security() != SEC_SHARE) {
1570 * In share level we should ignore any passwords, so
1571 * only read them if we're not.
1573 char *pass = NULL;
1574 bool unic= smb_flag2 & FLAGS2_UNICODE_STRINGS;
1576 if (unic && (passlen2 == 0) && passlen1) {
1577 /* Only a ascii plaintext password was sent. */
1578 (void)srvstr_pull_talloc(talloc_tos(),
1579 req->inbuf,
1580 req->flags2,
1581 &pass,
1582 req->buf,
1583 passlen1,
1584 STR_TERMINATE|STR_ASCII);
1585 } else {
1586 (void)srvstr_pull_talloc(talloc_tos(),
1587 req->inbuf,
1588 req->flags2,
1589 &pass,
1590 req->buf,
1591 unic ? passlen2 : passlen1,
1592 STR_TERMINATE);
1594 if (!pass) {
1595 reply_nterror(req, nt_status_squash(
1596 NT_STATUS_INVALID_PARAMETER));
1597 END_PROFILE(SMBsesssetupX);
1598 return;
1600 plaintext_password = data_blob(pass, strlen(pass)+1);
1603 p += passlen1 + passlen2;
1605 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1606 STR_TERMINATE);
1607 user = tmp ? tmp : "";
1609 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1610 STR_TERMINATE);
1611 domain = tmp ? tmp : "";
1613 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1614 STR_TERMINATE);
1615 native_os = tmp ? tmp : "";
1617 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1618 STR_TERMINATE);
1619 native_lanman = tmp ? tmp : "";
1621 /* not documented or decoded by Ethereal but there is one more
1622 * string in the extra bytes which is the same as the
1623 * PrimaryDomain when using extended security. Windows NT 4
1624 * and 2003 use this string to store the native lanman string.
1625 * Windows 9x does not include a string here at all so we have
1626 * to check if we have any extra bytes left */
1628 byte_count = SVAL(req->vwv+13, 0);
1629 if ( PTR_DIFF(p, save_p) < byte_count) {
1630 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1631 STR_TERMINATE);
1632 primary_domain = tmp ? tmp : "";
1633 } else {
1634 primary_domain = talloc_strdup(talloc_tos(), "null");
1637 DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s] "
1638 "PrimaryDomain=[%s]\n",
1639 domain, native_os, native_lanman, primary_domain));
1641 if ( ra_type == RA_WIN2K ) {
1642 if ( strlen(native_lanman) == 0 )
1643 ra_lanman_string( primary_domain );
1644 else
1645 ra_lanman_string( native_lanman );
1650 if (SVAL(req->vwv+4, 0) == 0) {
1651 setup_new_vc_session();
1654 DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n",
1655 domain, user, get_remote_machine_name()));
1657 if (*user) {
1658 if (sconn->smb1.negprot.spnego) {
1660 /* This has to be here, because this is a perfectly
1661 * valid behaviour for guest logons :-( */
1663 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt "
1664 "at 'normal' session setup after "
1665 "negotiating spnego.\n"));
1666 reply_nterror(req, nt_status_squash(
1667 NT_STATUS_LOGON_FAILURE));
1668 END_PROFILE(SMBsesssetupX);
1669 return;
1671 fstrcpy(sub_user, user);
1672 } else {
1673 fstrcpy(sub_user, lp_guestaccount());
1676 sub_set_smb_name(sub_user);
1678 reload_services(True);
1680 if (lp_security() == SEC_SHARE) {
1681 /* In share level we should ignore any passwords */
1683 data_blob_free(&lm_resp);
1684 data_blob_free(&nt_resp);
1685 data_blob_clear_free(&plaintext_password);
1687 map_username(sconn, sub_user);
1688 add_session_user(sconn, sub_user);
1689 add_session_workgroup(sconn, domain);
1690 /* Then force it to null for the benfit of the code below */
1691 user = "";
1694 if (!*user) {
1696 nt_status = check_guest_password(&server_info);
1698 } else if (doencrypt) {
1699 struct auth_context *negprot_auth_context = NULL;
1700 negprot_auth_context = sconn->smb1.negprot.auth_context;
1701 if (!negprot_auth_context) {
1702 DEBUG(0, ("reply_sesssetup_and_X: Attempted encrypted "
1703 "session setup without negprot denied!\n"));
1704 reply_nterror(req, nt_status_squash(
1705 NT_STATUS_LOGON_FAILURE));
1706 END_PROFILE(SMBsesssetupX);
1707 return;
1709 nt_status = make_user_info_for_reply_enc(&user_info, user,
1710 domain,
1711 lm_resp, nt_resp);
1712 if (NT_STATUS_IS_OK(nt_status)) {
1713 nt_status = negprot_auth_context->check_ntlm_password(
1714 negprot_auth_context,
1715 user_info,
1716 &server_info);
1718 } else {
1719 struct auth_context *plaintext_auth_context = NULL;
1721 nt_status = make_auth_context_subsystem(
1722 &plaintext_auth_context);
1724 if (NT_STATUS_IS_OK(nt_status)) {
1725 uint8_t chal[8];
1727 plaintext_auth_context->get_ntlm_challenge(
1728 plaintext_auth_context, chal);
1730 if (!make_user_info_for_reply(&user_info,
1731 user, domain, chal,
1732 plaintext_password)) {
1733 nt_status = NT_STATUS_NO_MEMORY;
1736 if (NT_STATUS_IS_OK(nt_status)) {
1737 nt_status = plaintext_auth_context->check_ntlm_password(
1738 plaintext_auth_context,
1739 user_info,
1740 &server_info);
1742 (plaintext_auth_context->free)(
1743 &plaintext_auth_context);
1748 free_user_info(&user_info);
1750 if (!NT_STATUS_IS_OK(nt_status)) {
1751 nt_status = do_map_to_guest(nt_status, &server_info,
1752 user, domain);
1755 if (!NT_STATUS_IS_OK(nt_status)) {
1756 data_blob_free(&nt_resp);
1757 data_blob_free(&lm_resp);
1758 data_blob_clear_free(&plaintext_password);
1759 reply_nterror(req, nt_status_squash(nt_status));
1760 END_PROFILE(SMBsesssetupX);
1761 return;
1764 /* Ensure we can't possible take a code path leading to a
1765 * null defref. */
1766 if (!server_info) {
1767 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1768 END_PROFILE(SMBsesssetupX);
1769 return;
1772 if (!server_info->ptok) {
1773 nt_status = create_local_token(server_info);
1775 if (!NT_STATUS_IS_OK(nt_status)) {
1776 DEBUG(10, ("create_local_token failed: %s\n",
1777 nt_errstr(nt_status)));
1778 data_blob_free(&nt_resp);
1779 data_blob_free(&lm_resp);
1780 data_blob_clear_free(&plaintext_password);
1781 reply_nterror(req, nt_status_squash(nt_status));
1782 END_PROFILE(SMBsesssetupX);
1783 return;
1787 data_blob_clear_free(&plaintext_password);
1789 /* it's ok - setup a reply */
1790 reply_outbuf(req, 3, 0);
1791 if (get_Protocol() >= PROTOCOL_NT1) {
1792 push_signature(&req->outbuf);
1793 /* perhaps grab OS version here?? */
1796 if (server_info->guest) {
1797 SSVAL(req->outbuf,smb_vwv2,1);
1800 /* register the name and uid as being validated, so further connections
1801 to a uid can get through without a password, on the same VC */
1803 if (lp_security() == SEC_SHARE) {
1804 sess_vuid = UID_FIELD_INVALID;
1805 TALLOC_FREE(server_info);
1806 } else {
1807 /* Ignore the initial vuid. */
1808 sess_vuid = register_initial_vuid(sconn);
1809 if (sess_vuid == UID_FIELD_INVALID) {
1810 data_blob_free(&nt_resp);
1811 data_blob_free(&lm_resp);
1812 reply_nterror(req, nt_status_squash(
1813 NT_STATUS_LOGON_FAILURE));
1814 END_PROFILE(SMBsesssetupX);
1815 return;
1817 /* register_existing_vuid keeps the server info */
1818 sess_vuid = register_existing_vuid(sconn, sess_vuid,
1819 server_info,
1820 nt_resp.data ? nt_resp : lm_resp,
1821 sub_user);
1822 if (sess_vuid == UID_FIELD_INVALID) {
1823 data_blob_free(&nt_resp);
1824 data_blob_free(&lm_resp);
1825 reply_nterror(req, nt_status_squash(
1826 NT_STATUS_LOGON_FAILURE));
1827 END_PROFILE(SMBsesssetupX);
1828 return;
1831 /* current_user_info is changed on new vuid */
1832 reload_services( True );
1835 data_blob_free(&nt_resp);
1836 data_blob_free(&lm_resp);
1838 SSVAL(req->outbuf,smb_uid,sess_vuid);
1839 SSVAL(req->inbuf,smb_uid,sess_vuid);
1840 req->vuid = sess_vuid;
1842 if (!sconn->smb1.sessions.done_sesssetup) {
1843 sconn->smb1.sessions.max_send =
1844 MIN(sconn->smb1.sessions.max_send,smb_bufsize);
1846 sconn->smb1.sessions.done_sesssetup = true;
1848 END_PROFILE(SMBsesssetupX);
1849 chain_reply(req);
1850 return;