format-subunit: Hide reason if it is None.
[Samba/eduardoll.git] / source3 / smbd / sesssetup.c
blob8c0317ae9eb28afd1e8b57eab87a4f6752343f5f
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"
30 /* For split krb5 SPNEGO blobs. */
31 struct pending_auth_data {
32 struct pending_auth_data *prev, *next;
33 uint16 vuid; /* Tag for this entry. */
34 uint16 smbpid; /* Alternate tag for this entry. */
35 size_t needed_len;
36 DATA_BLOB partial_data;
40 on a logon error possibly map the error to success if "map to guest"
41 is set approriately
43 static NTSTATUS do_map_to_guest(NTSTATUS status,
44 struct auth_serversupplied_info **server_info,
45 const char *user, const char *domain)
47 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
48 if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) ||
49 (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) {
50 DEBUG(3,("No such user %s [%s] - using guest account\n",
51 user, domain));
52 status = make_server_info_guest(NULL, server_info);
56 if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
57 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) {
58 DEBUG(3,("Registered username %s for guest access\n",
59 user));
60 status = make_server_info_guest(NULL, server_info);
64 return status;
67 /****************************************************************************
68 Add the standard 'Samba' signature to the end of the session setup.
69 ****************************************************************************/
71 static int push_signature(uint8 **outbuf)
73 char *lanman;
74 int result, tmp;
76 result = 0;
78 tmp = message_push_string(outbuf, "Unix", STR_TERMINATE);
80 if (tmp == -1) return -1;
81 result += tmp;
83 if (asprintf(&lanman, "Samba %s", samba_version_string()) != -1) {
84 tmp = message_push_string(outbuf, lanman, STR_TERMINATE);
85 SAFE_FREE(lanman);
87 else {
88 tmp = message_push_string(outbuf, "Samba", STR_TERMINATE);
91 if (tmp == -1) return -1;
92 result += tmp;
94 tmp = message_push_string(outbuf, lp_workgroup(), STR_TERMINATE);
96 if (tmp == -1) return -1;
97 result += tmp;
99 return result;
102 /****************************************************************************
103 Send a security blob via a session setup reply.
104 ****************************************************************************/
106 static void reply_sesssetup_blob(struct smb_request *req,
107 DATA_BLOB blob,
108 NTSTATUS nt_status)
110 if (!NT_STATUS_IS_OK(nt_status) &&
111 !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
112 reply_nterror(req, nt_status_squash(nt_status));
113 return;
116 nt_status = nt_status_squash(nt_status);
117 SIVAL(req->outbuf, smb_rcls, NT_STATUS_V(nt_status));
118 SSVAL(req->outbuf, smb_vwv0, 0xFF); /* no chaining possible */
119 SSVAL(req->outbuf, smb_vwv3, blob.length);
121 if ((message_push_blob(&req->outbuf, blob) == -1)
122 || (push_signature(&req->outbuf) == -1)) {
123 reply_nterror(req, NT_STATUS_NO_MEMORY);
127 /****************************************************************************
128 Do a 'guest' logon, getting back the
129 ****************************************************************************/
131 static NTSTATUS check_guest_password(struct auth_serversupplied_info **server_info)
133 struct auth_context *auth_context;
134 struct auth_usersupplied_info *user_info = NULL;
136 NTSTATUS nt_status;
137 unsigned char chal[8];
139 ZERO_STRUCT(chal);
141 DEBUG(3,("Got anonymous request\n"));
143 if (!NT_STATUS_IS_OK(nt_status = make_auth_context_fixed(&auth_context,
144 chal))) {
145 return nt_status;
148 if (!make_user_info_guest(&user_info)) {
149 (auth_context->free)(&auth_context);
150 return NT_STATUS_NO_MEMORY;
153 nt_status = auth_context->check_ntlm_password(auth_context,
154 user_info,
155 server_info);
156 (auth_context->free)(&auth_context);
157 free_user_info(&user_info);
158 return nt_status;
162 #ifdef HAVE_KRB5
164 #if 0
165 /* Experiment that failed. See "only happens with a KDC" comment below. */
166 /****************************************************************************
167 Cerate a clock skew error blob for a Windows client.
168 ****************************************************************************/
170 static bool make_krb5_skew_error(DATA_BLOB *pblob_out)
172 krb5_context context = NULL;
173 krb5_error_code kerr = 0;
174 krb5_data reply;
175 krb5_principal host_princ = NULL;
176 char *host_princ_s = NULL;
177 bool ret = False;
179 *pblob_out = data_blob_null;
181 initialize_krb5_error_table();
182 kerr = krb5_init_context(&context);
183 if (kerr) {
184 return False;
186 /* Create server principal. */
187 asprintf(&host_princ_s, "%s$@%s", global_myname(), lp_realm());
188 if (!host_princ_s) {
189 goto out;
191 strlower_m(host_princ_s);
193 kerr = smb_krb5_parse_name(context, host_princ_s, &host_princ);
194 if (kerr) {
195 DEBUG(10,("make_krb5_skew_error: smb_krb5_parse_name failed "
196 "for name %s: Error %s\n",
197 host_princ_s, error_message(kerr) ));
198 goto out;
201 kerr = smb_krb5_mk_error(context, KRB5KRB_AP_ERR_SKEW,
202 host_princ, &reply);
203 if (kerr) {
204 DEBUG(10,("make_krb5_skew_error: smb_krb5_mk_error "
205 "failed: Error %s\n",
206 error_message(kerr) ));
207 goto out;
210 *pblob_out = data_blob(reply.data, reply.length);
211 kerberos_free_data_contents(context,&reply);
212 ret = True;
214 out:
216 if (host_princ_s) {
217 SAFE_FREE(host_princ_s);
219 if (host_princ) {
220 krb5_free_principal(context, host_princ);
222 krb5_free_context(context);
223 return ret;
225 #endif
227 /****************************************************************************
228 Reply to a session setup spnego negotiate packet for kerberos.
229 ****************************************************************************/
231 static void reply_spnego_kerberos(struct smb_request *req,
232 DATA_BLOB *secblob,
233 const char *mechOID,
234 uint16 vuid,
235 bool *p_invalidate_vuid)
237 TALLOC_CTX *mem_ctx;
238 DATA_BLOB ticket;
239 char *client, *p, *domain;
240 fstring netbios_domain_name;
241 struct passwd *pw;
242 fstring user;
243 int sess_vuid = req->vuid;
244 NTSTATUS ret = NT_STATUS_OK;
245 struct PAC_DATA *pac_data = NULL;
246 DATA_BLOB ap_rep, ap_rep_wrapped, response;
247 struct auth_serversupplied_info *server_info = NULL;
248 DATA_BLOB session_key = data_blob_null;
249 uint8 tok_id[2];
250 DATA_BLOB nullblob = data_blob_null;
251 fstring real_username;
252 bool map_domainuser_to_guest = False;
253 bool username_was_mapped;
254 struct PAC_LOGON_INFO *logon_info = NULL;
255 struct smbd_server_connection *sconn = smbd_server_conn;
257 ZERO_STRUCT(ticket);
258 ZERO_STRUCT(ap_rep);
259 ZERO_STRUCT(ap_rep_wrapped);
260 ZERO_STRUCT(response);
262 /* Normally we will always invalidate the intermediate vuid. */
263 *p_invalidate_vuid = True;
265 mem_ctx = talloc_init("reply_spnego_kerberos");
266 if (mem_ctx == NULL) {
267 reply_nterror(req, nt_status_squash(NT_STATUS_NO_MEMORY));
268 return;
271 if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) {
272 talloc_destroy(mem_ctx);
273 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
274 return;
277 ret = ads_verify_ticket(mem_ctx, lp_realm(), 0, &ticket,
278 &client, &pac_data, &ap_rep,
279 &session_key, True);
281 data_blob_free(&ticket);
283 if (!NT_STATUS_IS_OK(ret)) {
284 #if 0
285 /* Experiment that failed.
286 * See "only happens with a KDC" comment below. */
288 if (NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
291 * Windows in this case returns
292 * NT_STATUS_MORE_PROCESSING_REQUIRED
293 * with a negTokenTarg blob containing an krb5_error
294 * struct ASN1 encoded containing KRB5KRB_AP_ERR_SKEW.
295 * The client then fixes its clock and continues rather
296 * than giving an error. JRA.
297 * -- Looks like this only happens with a KDC. JRA.
300 bool ok = make_krb5_skew_error(&ap_rep);
301 if (!ok) {
302 talloc_destroy(mem_ctx);
303 return ERROR_NT(nt_status_squash(
304 NT_STATUS_LOGON_FAILURE));
306 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep,
307 TOK_ID_KRB_ERROR);
308 response = spnego_gen_auth_response(&ap_rep_wrapped,
309 ret, OID_KERBEROS5_OLD);
310 reply_sesssetup_blob(conn, inbuf, outbuf, response,
311 NT_STATUS_MORE_PROCESSING_REQUIRED);
314 * In this one case we don't invalidate the
315 * intermediate vuid as we're expecting the client
316 * to re-use it for the next sessionsetupX packet. JRA.
319 *p_invalidate_vuid = False;
321 data_blob_free(&ap_rep);
322 data_blob_free(&ap_rep_wrapped);
323 data_blob_free(&response);
324 talloc_destroy(mem_ctx);
325 return -1; /* already replied */
327 #else
328 if (!NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
329 ret = NT_STATUS_LOGON_FAILURE;
331 #endif
332 DEBUG(1,("Failed to verify incoming ticket with error %s!\n",
333 nt_errstr(ret)));
334 talloc_destroy(mem_ctx);
335 reply_nterror(req, nt_status_squash(ret));
336 return;
339 DEBUG(3,("Ticket name is [%s]\n", client));
341 p = strchr_m(client, '@');
342 if (!p) {
343 DEBUG(3,("Doesn't look like a valid principal\n"));
344 data_blob_free(&ap_rep);
345 data_blob_free(&session_key);
346 talloc_destroy(mem_ctx);
347 reply_nterror(req,nt_status_squash(NT_STATUS_LOGON_FAILURE));
348 return;
351 *p = 0;
353 /* save the PAC data if we have it */
355 if (pac_data) {
356 logon_info = get_logon_info_from_pac(pac_data);
357 if (logon_info) {
358 netsamlogon_cache_store( client, &logon_info->info3 );
362 if (!strequal(p+1, lp_realm())) {
363 DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1));
364 if (!lp_allow_trusted_domains()) {
365 data_blob_free(&ap_rep);
366 data_blob_free(&session_key);
367 talloc_destroy(mem_ctx);
368 reply_nterror(req, nt_status_squash(
369 NT_STATUS_LOGON_FAILURE));
370 return;
374 /* this gives a fully qualified user name (ie. with full realm).
375 that leads to very long usernames, but what else can we do? */
377 domain = p+1;
379 if (logon_info && logon_info->info3.base.domain.string) {
380 fstrcpy(netbios_domain_name,
381 logon_info->info3.base.domain.string);
382 domain = netbios_domain_name;
383 DEBUG(10, ("Mapped to [%s] (using PAC)\n", domain));
385 } else {
387 /* If we have winbind running, we can (and must) shorten the
388 username by using the short netbios name. Otherwise we will
389 have inconsistent user names. With Kerberos, we get the
390 fully qualified realm, with ntlmssp we get the short
391 name. And even w2k3 does use ntlmssp if you for example
392 connect to an ip address. */
394 wbcErr wbc_status;
395 struct wbcDomainInfo *info = NULL;
397 DEBUG(10, ("Mapping [%s] to short name\n", domain));
399 wbc_status = wbcDomainInfo(domain, &info);
401 if (WBC_ERROR_IS_OK(wbc_status)) {
403 fstrcpy(netbios_domain_name,
404 info->short_name);
406 wbcFreeMemory(info);
407 domain = netbios_domain_name;
408 DEBUG(10, ("Mapped to [%s] (using Winbind)\n", domain));
409 } else {
410 DEBUG(3, ("Could not find short name: %s\n",
411 wbcErrorString(wbc_status)));
415 fstr_sprintf(user, "%s%c%s", domain, *lp_winbind_separator(), client);
417 /* lookup the passwd struct, create a new user if necessary */
419 username_was_mapped = map_username(sconn, user);
421 pw = smb_getpwnam( mem_ctx, user, real_username, True );
423 if (pw) {
424 /* if a real user check pam account restrictions */
425 /* only really perfomed if "obey pam restriction" is true */
426 /* do this before an eventual mapping to guest occurs */
427 ret = smb_pam_accountcheck(pw->pw_name);
428 if ( !NT_STATUS_IS_OK(ret)) {
429 DEBUG(1,("PAM account restriction "
430 "prevents user login\n"));
431 data_blob_free(&ap_rep);
432 data_blob_free(&session_key);
433 TALLOC_FREE(mem_ctx);
434 reply_nterror(req, nt_status_squash(ret));
435 return;
439 if (!pw) {
441 /* this was originally the behavior of Samba 2.2, if a user
442 did not have a local uid but has been authenticated, then
443 map them to a guest account */
445 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID){
446 map_domainuser_to_guest = True;
447 fstrcpy(user,lp_guestaccount());
448 pw = smb_getpwnam( mem_ctx, user, real_username, True );
451 /* extra sanity check that the guest account is valid */
453 if ( !pw ) {
454 DEBUG(1,("Username %s is invalid on this system\n",
455 user));
456 data_blob_free(&ap_rep);
457 data_blob_free(&session_key);
458 TALLOC_FREE(mem_ctx);
459 reply_nterror(req, nt_status_squash(
460 NT_STATUS_LOGON_FAILURE));
461 return;
465 /* setup the string used by %U */
467 sub_set_smb_name( real_username );
468 reload_services(True);
470 if ( map_domainuser_to_guest ) {
471 make_server_info_guest(NULL, &server_info);
472 } else if (logon_info) {
473 /* pass the unmapped username here since map_username()
474 will be called again from inside make_server_info_info3() */
476 ret = make_server_info_info3(mem_ctx, client, domain,
477 &server_info, &logon_info->info3);
478 if ( !NT_STATUS_IS_OK(ret) ) {
479 DEBUG(1,("make_server_info_info3 failed: %s!\n",
480 nt_errstr(ret)));
481 data_blob_free(&ap_rep);
482 data_blob_free(&session_key);
483 TALLOC_FREE(mem_ctx);
484 reply_nterror(req, nt_status_squash(ret));
485 return;
488 } else {
490 * We didn't get a PAC, we have to make up the user
491 * ourselves. Try to ask the pdb backend to provide
492 * SID consistency with ntlmssp session setup
494 struct samu *sampass;
496 sampass = samu_new(talloc_tos());
497 if (sampass == NULL) {
498 ret = NT_STATUS_NO_MEMORY;
499 data_blob_free(&ap_rep);
500 data_blob_free(&session_key);
501 TALLOC_FREE(mem_ctx);
502 reply_nterror(req, nt_status_squash(ret));
503 return;
506 if (pdb_getsampwnam(sampass, real_username)) {
507 DEBUG(10, ("found user %s in passdb, calling "
508 "make_server_info_sam\n", real_username));
509 ret = make_server_info_sam(&server_info, sampass);
510 } else {
512 * User not in passdb, make it up artificially
514 TALLOC_FREE(sampass);
515 DEBUG(10, ("didn't find user %s in passdb, calling "
516 "make_server_info_pw\n", real_username));
517 ret = make_server_info_pw(&server_info, real_username,
518 pw);
521 if ( !NT_STATUS_IS_OK(ret) ) {
522 DEBUG(1,("make_server_info_[sam|pw] failed: %s!\n",
523 nt_errstr(ret)));
524 data_blob_free(&ap_rep);
525 data_blob_free(&session_key);
526 TALLOC_FREE(mem_ctx);
527 reply_nterror(req, nt_status_squash(ret));
528 return;
531 /* make_server_info_pw does not set the domain. Without this
532 * we end up with the local netbios name in substitutions for
533 * %D. */
535 if (server_info->sam_account != NULL) {
536 pdb_set_domain(server_info->sam_account,
537 domain, PDB_SET);
541 server_info->nss_token |= username_was_mapped;
543 /* we need to build the token for the user. make_server_info_guest()
544 already does this */
546 if ( !server_info->ptok ) {
547 ret = create_local_token( server_info );
548 if ( !NT_STATUS_IS_OK(ret) ) {
549 DEBUG(10,("failed to create local token: %s\n",
550 nt_errstr(ret)));
551 data_blob_free(&ap_rep);
552 data_blob_free(&session_key);
553 TALLOC_FREE( mem_ctx );
554 TALLOC_FREE( server_info );
555 reply_nterror(req, nt_status_squash(ret));
556 return;
560 if (!is_partial_auth_vuid(sconn, sess_vuid)) {
561 sess_vuid = register_initial_vuid(sconn);
564 data_blob_free(&server_info->user_session_key);
565 server_info->user_session_key = session_key;
566 session_key = data_blob_null;
568 /* register_existing_vuid keeps the server info */
569 /* register_existing_vuid takes ownership of session_key on success,
570 * no need to free after this on success. A better interface would copy
571 * it.... */
573 sess_vuid = register_existing_vuid(sconn,
574 sess_vuid,
575 server_info,
576 nullblob,
577 client);
579 reply_outbuf(req, 4, 0);
580 SSVAL(req->outbuf,smb_uid,sess_vuid);
582 if (sess_vuid == UID_FIELD_INVALID ) {
583 ret = NT_STATUS_LOGON_FAILURE;
584 } else {
585 /* current_user_info is changed on new vuid */
586 reload_services( True );
588 SSVAL(req->outbuf, smb_vwv3, 0);
590 if (server_info->guest) {
591 SSVAL(req->outbuf,smb_vwv2,1);
594 SSVAL(req->outbuf, smb_uid, sess_vuid);
596 /* Successful logon. Keep this vuid. */
597 *p_invalidate_vuid = False;
600 /* wrap that up in a nice GSS-API wrapping */
601 if (NT_STATUS_IS_OK(ret)) {
602 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep,
603 TOK_ID_KRB_AP_REP);
604 } else {
605 ap_rep_wrapped = data_blob_null;
607 response = spnego_gen_auth_response(&ap_rep_wrapped, ret,
608 mechOID);
609 reply_sesssetup_blob(req, response, ret);
611 data_blob_free(&ap_rep);
612 data_blob_free(&ap_rep_wrapped);
613 data_blob_free(&response);
614 TALLOC_FREE(mem_ctx);
617 #endif
619 /****************************************************************************
620 Send a session setup reply, wrapped in SPNEGO.
621 Get vuid and check first.
622 End the NTLMSSP exchange context if we are OK/complete fail
623 This should be split into two functions, one to handle each
624 leg of the NTLM auth steps.
625 ***************************************************************************/
627 static void reply_spnego_ntlmssp(struct smb_request *req,
628 uint16 vuid,
629 AUTH_NTLMSSP_STATE **auth_ntlmssp_state,
630 DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status,
631 const char *OID,
632 bool wrap)
634 DATA_BLOB response;
635 struct auth_serversupplied_info *server_info = NULL;
636 struct smbd_server_connection *sconn = smbd_server_conn;
638 if (NT_STATUS_IS_OK(nt_status)) {
639 server_info = (*auth_ntlmssp_state)->server_info;
640 } else {
641 nt_status = do_map_to_guest(nt_status,
642 &server_info,
643 (*auth_ntlmssp_state)->ntlmssp_state->user,
644 (*auth_ntlmssp_state)->ntlmssp_state->domain);
647 reply_outbuf(req, 4, 0);
649 SSVAL(req->outbuf, smb_uid, vuid);
651 if (NT_STATUS_IS_OK(nt_status)) {
652 DATA_BLOB nullblob = data_blob_null;
654 if (!is_partial_auth_vuid(sconn, vuid)) {
655 nt_status = NT_STATUS_LOGON_FAILURE;
656 goto out;
659 data_blob_free(&server_info->user_session_key);
660 server_info->user_session_key =
661 data_blob_talloc(
662 server_info,
663 (*auth_ntlmssp_state)->ntlmssp_state->session_key.data,
664 (*auth_ntlmssp_state)->ntlmssp_state->session_key.length);
666 /* register_existing_vuid keeps the server info */
667 if (register_existing_vuid(sconn, vuid,
668 server_info, nullblob,
669 (*auth_ntlmssp_state)->ntlmssp_state->user) !=
670 vuid) {
671 nt_status = NT_STATUS_LOGON_FAILURE;
672 goto out;
675 (*auth_ntlmssp_state)->server_info = NULL;
677 /* current_user_info is changed on new vuid */
678 reload_services( True );
680 SSVAL(req->outbuf, smb_vwv3, 0);
682 if (server_info->guest) {
683 SSVAL(req->outbuf,smb_vwv2,1);
687 out:
689 if (wrap) {
690 response = spnego_gen_auth_response(ntlmssp_blob,
691 nt_status, OID);
692 } else {
693 response = *ntlmssp_blob;
696 reply_sesssetup_blob(req, response, nt_status);
697 if (wrap) {
698 data_blob_free(&response);
701 /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
702 and the other end, that we are not finished yet. */
704 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
705 /* NB. This is *NOT* an error case. JRA */
706 auth_ntlmssp_end(auth_ntlmssp_state);
707 if (!NT_STATUS_IS_OK(nt_status)) {
708 /* Kill the intermediate vuid */
709 invalidate_vuid(sconn, vuid);
714 /****************************************************************************
715 Is this a krb5 mechanism ?
716 ****************************************************************************/
718 NTSTATUS parse_spnego_mechanisms(DATA_BLOB blob_in,
719 DATA_BLOB *pblob_out,
720 char **kerb_mechOID)
722 char *OIDs[ASN1_MAX_OIDS];
723 int i;
724 NTSTATUS ret = NT_STATUS_OK;
726 *kerb_mechOID = NULL;
728 /* parse out the OIDs and the first sec blob */
729 if (!parse_negTokenTarg(blob_in, OIDs, pblob_out)) {
730 return NT_STATUS_LOGON_FAILURE;
733 /* only look at the first OID for determining the mechToken --
734 according to RFC2478, we should choose the one we want
735 and renegotiate, but i smell a client bug here..
737 Problem observed when connecting to a member (samba box)
738 of an AD domain as a user in a Samba domain. Samba member
739 server sent back krb5/mskrb5/ntlmssp as mechtypes, but the
740 client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an
741 NTLMSSP mechtoken. --jerry */
743 #ifdef HAVE_KRB5
744 if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||
745 strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
746 *kerb_mechOID = SMB_STRDUP(OIDs[0]);
747 if (*kerb_mechOID == NULL) {
748 ret = NT_STATUS_NO_MEMORY;
751 #endif
753 for (i=0;OIDs[i];i++) {
754 DEBUG(5,("parse_spnego_mechanisms: Got OID %s\n", OIDs[i]));
755 talloc_free(OIDs[i]);
757 return ret;
760 /****************************************************************************
761 Fall back from krb5 to NTLMSSP.
762 ****************************************************************************/
764 static void reply_spnego_downgrade_to_ntlmssp(struct smb_request *req,
765 uint16 vuid)
767 DATA_BLOB response;
769 reply_outbuf(req, 4, 0);
770 SSVAL(req->outbuf,smb_uid,vuid);
772 DEBUG(3,("reply_spnego_downgrade_to_ntlmssp: Got krb5 ticket in SPNEGO "
773 "but set to downgrade to NTLMSSP\n"));
775 response = spnego_gen_auth_response(NULL,
776 NT_STATUS_MORE_PROCESSING_REQUIRED,
777 OID_NTLMSSP);
778 reply_sesssetup_blob(req, response, NT_STATUS_MORE_PROCESSING_REQUIRED);
779 data_blob_free(&response);
782 /****************************************************************************
783 Reply to a session setup spnego negotiate packet.
784 ****************************************************************************/
786 static void reply_spnego_negotiate(struct smb_request *req,
787 uint16 vuid,
788 DATA_BLOB blob1,
789 AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
791 DATA_BLOB secblob;
792 DATA_BLOB chal;
793 char *kerb_mech = NULL;
794 NTSTATUS status;
795 struct smbd_server_connection *sconn = smbd_server_conn;
797 status = parse_spnego_mechanisms(blob1, &secblob, &kerb_mech);
798 if (!NT_STATUS_IS_OK(status)) {
799 /* Kill the intermediate vuid */
800 invalidate_vuid(sconn, vuid);
801 reply_nterror(req, nt_status_squash(status));
802 return;
805 DEBUG(3,("reply_spnego_negotiate: Got secblob of size %lu\n",
806 (unsigned long)secblob.length));
808 #ifdef HAVE_KRB5
809 if (kerb_mech && ((lp_security()==SEC_ADS) ||
810 USE_KERBEROS_KEYTAB) ) {
811 bool destroy_vuid = True;
812 reply_spnego_kerberos(req, &secblob, kerb_mech,
813 vuid, &destroy_vuid);
814 data_blob_free(&secblob);
815 if (destroy_vuid) {
816 /* Kill the intermediate vuid */
817 invalidate_vuid(sconn, vuid);
819 SAFE_FREE(kerb_mech);
820 return;
822 #endif
824 if (*auth_ntlmssp_state) {
825 auth_ntlmssp_end(auth_ntlmssp_state);
828 if (kerb_mech) {
829 data_blob_free(&secblob);
830 /* The mechtoken is a krb5 ticket, but
831 * we need to fall back to NTLM. */
832 reply_spnego_downgrade_to_ntlmssp(req, vuid);
833 SAFE_FREE(kerb_mech);
834 return;
837 status = auth_ntlmssp_start(auth_ntlmssp_state);
838 if (!NT_STATUS_IS_OK(status)) {
839 /* Kill the intermediate vuid */
840 invalidate_vuid(sconn, vuid);
841 reply_nterror(req, nt_status_squash(status));
842 return;
845 status = auth_ntlmssp_update(*auth_ntlmssp_state,
846 secblob, &chal);
848 data_blob_free(&secblob);
850 reply_spnego_ntlmssp(req, vuid, auth_ntlmssp_state,
851 &chal, status, OID_NTLMSSP, true);
853 data_blob_free(&chal);
855 /* already replied */
856 return;
859 /****************************************************************************
860 Reply to a session setup spnego auth packet.
861 ****************************************************************************/
863 static void reply_spnego_auth(struct smb_request *req,
864 uint16 vuid,
865 DATA_BLOB blob1,
866 AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
868 DATA_BLOB auth = data_blob_null;
869 DATA_BLOB auth_reply = data_blob_null;
870 DATA_BLOB secblob = data_blob_null;
871 NTSTATUS status = NT_STATUS_LOGON_FAILURE;
872 struct smbd_server_connection *sconn = smbd_server_conn;
874 if (!spnego_parse_auth(blob1, &auth)) {
875 #if 0
876 file_save("auth.dat", blob1.data, blob1.length);
877 #endif
878 /* Kill the intermediate vuid */
879 invalidate_vuid(sconn, vuid);
881 reply_nterror(req, nt_status_squash(
882 NT_STATUS_LOGON_FAILURE));
883 return;
886 if (auth.data[0] == ASN1_APPLICATION(0)) {
887 /* Might be a second negTokenTarg packet */
888 char *kerb_mech = NULL;
890 status = parse_spnego_mechanisms(auth, &secblob, &kerb_mech);
892 if (!NT_STATUS_IS_OK(status)) {
893 /* Kill the intermediate vuid */
894 invalidate_vuid(sconn, vuid);
895 reply_nterror(req, nt_status_squash(status));
896 return;
899 DEBUG(3,("reply_spnego_auth: Got secblob of size %lu\n",
900 (unsigned long)secblob.length));
901 #ifdef HAVE_KRB5
902 if (kerb_mech && ((lp_security()==SEC_ADS) ||
903 USE_KERBEROS_KEYTAB)) {
904 bool destroy_vuid = True;
905 reply_spnego_kerberos(req, &secblob, kerb_mech,
906 vuid, &destroy_vuid);
907 data_blob_free(&secblob);
908 data_blob_free(&auth);
909 if (destroy_vuid) {
910 /* Kill the intermediate vuid */
911 invalidate_vuid(sconn, vuid);
913 SAFE_FREE(kerb_mech);
914 return;
916 #endif
917 /* Can't blunder into NTLMSSP auth if we have
918 * a krb5 ticket. */
920 if (kerb_mech) {
921 /* Kill the intermediate vuid */
922 invalidate_vuid(sconn, vuid);
923 DEBUG(3,("reply_spnego_auth: network "
924 "misconfiguration, client sent us a "
925 "krb5 ticket and kerberos security "
926 "not enabled\n"));
927 reply_nterror(req, nt_status_squash(
928 NT_STATUS_LOGON_FAILURE));
929 SAFE_FREE(kerb_mech);
933 /* If we get here it wasn't a negTokenTarg auth packet. */
934 data_blob_free(&secblob);
936 if (!*auth_ntlmssp_state) {
937 status = auth_ntlmssp_start(auth_ntlmssp_state);
938 if (!NT_STATUS_IS_OK(status)) {
939 /* Kill the intermediate vuid */
940 invalidate_vuid(sconn, vuid);
941 reply_nterror(req, nt_status_squash(status));
942 return;
946 status = auth_ntlmssp_update(*auth_ntlmssp_state,
947 auth, &auth_reply);
949 data_blob_free(&auth);
951 /* Don't send the mechid as we've already sent this (RFC4178). */
953 reply_spnego_ntlmssp(req, vuid,
954 auth_ntlmssp_state,
955 &auth_reply, status, NULL, true);
957 data_blob_free(&auth_reply);
959 /* and tell smbd that we have already replied to this packet */
960 return;
963 /****************************************************************************
964 Delete an entry on the list.
965 ****************************************************************************/
967 static void delete_partial_auth(struct smbd_server_connection *sconn,
968 struct pending_auth_data *pad)
970 if (!pad) {
971 return;
973 DLIST_REMOVE(sconn->smb1.pd_list, pad);
974 data_blob_free(&pad->partial_data);
975 SAFE_FREE(pad);
978 /****************************************************************************
979 Search for a partial SPNEGO auth fragment matching an smbpid.
980 ****************************************************************************/
982 static struct pending_auth_data *get_pending_auth_data(
983 struct smbd_server_connection *sconn,
984 uint16_t smbpid)
986 struct pending_auth_data *pad;
988 * NOTE: using the smbpid here is completely wrong...
989 * see [MS-SMB]
990 * 3.3.5.3 Receiving an SMB_COM_SESSION_SETUP_ANDX Request
992 for (pad = sconn->smb1.pd_list; pad; pad = pad->next) {
993 if (pad->smbpid == smbpid) {
994 break;
997 return pad;
1000 /****************************************************************************
1001 Check the size of an SPNEGO blob. If we need more return
1002 NT_STATUS_MORE_PROCESSING_REQUIRED, else return NT_STATUS_OK. Don't allow
1003 the blob to be more than 64k.
1004 ****************************************************************************/
1006 static NTSTATUS check_spnego_blob_complete(struct smbd_server_connection *sconn,
1007 uint16 smbpid, uint16 vuid,
1008 DATA_BLOB *pblob)
1010 struct pending_auth_data *pad = NULL;
1011 ASN1_DATA *data;
1012 size_t needed_len = 0;
1014 pad = get_pending_auth_data(sconn, smbpid);
1016 /* Ensure we have some data. */
1017 if (pblob->length == 0) {
1018 /* Caller can cope. */
1019 DEBUG(2,("check_spnego_blob_complete: zero blob length !\n"));
1020 delete_partial_auth(sconn, pad);
1021 return NT_STATUS_OK;
1024 /* Were we waiting for more data ? */
1025 if (pad) {
1026 DATA_BLOB tmp_blob;
1027 size_t copy_len = MIN(65536, pblob->length);
1029 /* Integer wrap paranoia.... */
1031 if (pad->partial_data.length + copy_len <
1032 pad->partial_data.length ||
1033 pad->partial_data.length + copy_len < copy_len) {
1035 DEBUG(2,("check_spnego_blob_complete: integer wrap "
1036 "pad->partial_data.length = %u, "
1037 "copy_len = %u\n",
1038 (unsigned int)pad->partial_data.length,
1039 (unsigned int)copy_len ));
1041 delete_partial_auth(sconn, pad);
1042 return NT_STATUS_INVALID_PARAMETER;
1045 DEBUG(10,("check_spnego_blob_complete: "
1046 "pad->partial_data.length = %u, "
1047 "pad->needed_len = %u, "
1048 "copy_len = %u, "
1049 "pblob->length = %u,\n",
1050 (unsigned int)pad->partial_data.length,
1051 (unsigned int)pad->needed_len,
1052 (unsigned int)copy_len,
1053 (unsigned int)pblob->length ));
1055 tmp_blob = data_blob(NULL,
1056 pad->partial_data.length + copy_len);
1058 /* Concatenate the two (up to copy_len) bytes. */
1059 memcpy(tmp_blob.data,
1060 pad->partial_data.data,
1061 pad->partial_data.length);
1062 memcpy(tmp_blob.data + pad->partial_data.length,
1063 pblob->data,
1064 copy_len);
1066 /* Replace the partial data. */
1067 data_blob_free(&pad->partial_data);
1068 pad->partial_data = tmp_blob;
1069 ZERO_STRUCT(tmp_blob);
1071 /* Are we done ? */
1072 if (pblob->length >= pad->needed_len) {
1073 /* Yes, replace pblob. */
1074 data_blob_free(pblob);
1075 *pblob = pad->partial_data;
1076 ZERO_STRUCT(pad->partial_data);
1077 delete_partial_auth(sconn, pad);
1078 return NT_STATUS_OK;
1081 /* Still need more data. */
1082 pad->needed_len -= copy_len;
1083 return NT_STATUS_MORE_PROCESSING_REQUIRED;
1086 if ((pblob->data[0] != ASN1_APPLICATION(0)) &&
1087 (pblob->data[0] != ASN1_CONTEXT(1))) {
1088 /* Not something we can determine the
1089 * length of.
1091 return NT_STATUS_OK;
1094 /* This is a new SPNEGO sessionsetup - see if
1095 * the data given in this blob is enough.
1098 data = asn1_init(NULL);
1099 if (data == NULL) {
1100 return NT_STATUS_NO_MEMORY;
1103 asn1_load(data, *pblob);
1104 asn1_start_tag(data, pblob->data[0]);
1105 if (data->has_error || data->nesting == NULL) {
1106 asn1_free(data);
1107 /* Let caller catch. */
1108 return NT_STATUS_OK;
1111 /* Integer wrap paranoia.... */
1113 if (data->nesting->taglen + data->nesting->start < data->nesting->taglen ||
1114 data->nesting->taglen + data->nesting->start < data->nesting->start) {
1116 DEBUG(2,("check_spnego_blob_complete: integer wrap "
1117 "data.nesting->taglen = %u, "
1118 "data.nesting->start = %u\n",
1119 (unsigned int)data->nesting->taglen,
1120 (unsigned int)data->nesting->start ));
1122 asn1_free(data);
1123 return NT_STATUS_INVALID_PARAMETER;
1126 /* Total length of the needed asn1 is the tag length
1127 * plus the current offset. */
1129 needed_len = data->nesting->taglen + data->nesting->start;
1130 asn1_free(data);
1132 DEBUG(10,("check_spnego_blob_complete: needed_len = %u, "
1133 "pblob->length = %u\n",
1134 (unsigned int)needed_len,
1135 (unsigned int)pblob->length ));
1137 if (needed_len <= pblob->length) {
1138 /* Nothing to do - blob is complete. */
1139 return NT_STATUS_OK;
1142 /* Refuse the blob if it's bigger than 64k. */
1143 if (needed_len > 65536) {
1144 DEBUG(2,("check_spnego_blob_complete: needed_len "
1145 "too large (%u)\n",
1146 (unsigned int)needed_len ));
1147 return NT_STATUS_INVALID_PARAMETER;
1150 /* We must store this blob until complete. */
1151 if (!(pad = SMB_MALLOC_P(struct pending_auth_data))) {
1152 return NT_STATUS_NO_MEMORY;
1154 pad->needed_len = needed_len - pblob->length;
1155 pad->partial_data = data_blob(pblob->data, pblob->length);
1156 if (pad->partial_data.data == NULL) {
1157 SAFE_FREE(pad);
1158 return NT_STATUS_NO_MEMORY;
1160 pad->smbpid = smbpid;
1161 pad->vuid = vuid;
1162 DLIST_ADD(sconn->smb1.pd_list, pad);
1164 return NT_STATUS_MORE_PROCESSING_REQUIRED;
1167 /****************************************************************************
1168 Reply to a session setup command.
1169 conn POINTER CAN BE NULL HERE !
1170 ****************************************************************************/
1172 static void reply_sesssetup_and_X_spnego(struct smb_request *req)
1174 const uint8 *p;
1175 DATA_BLOB blob1;
1176 size_t bufrem;
1177 char *tmp;
1178 const char *native_os;
1179 const char *native_lanman;
1180 const char *primary_domain;
1181 const char *p2;
1182 uint16 data_blob_len = SVAL(req->vwv+7, 0);
1183 enum remote_arch_types ra_type = get_remote_arch();
1184 int vuid = req->vuid;
1185 user_struct *vuser = NULL;
1186 NTSTATUS status = NT_STATUS_OK;
1187 uint16 smbpid = req->smbpid;
1188 struct smbd_server_connection *sconn = smbd_server_conn;
1190 DEBUG(3,("Doing spnego session setup\n"));
1192 if (global_client_caps == 0) {
1193 global_client_caps = IVAL(req->vwv+10, 0);
1195 if (!(global_client_caps & CAP_STATUS32)) {
1196 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1201 p = req->buf;
1203 if (data_blob_len == 0) {
1204 /* an invalid request */
1205 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1206 return;
1209 bufrem = smbreq_bufrem(req, p);
1210 /* pull the spnego blob */
1211 blob1 = data_blob(p, MIN(bufrem, data_blob_len));
1213 #if 0
1214 file_save("negotiate.dat", blob1.data, blob1.length);
1215 #endif
1217 p2 = (char *)req->buf + blob1.length;
1219 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1220 STR_TERMINATE);
1221 native_os = tmp ? tmp : "";
1223 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1224 STR_TERMINATE);
1225 native_lanman = tmp ? tmp : "";
1227 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1228 STR_TERMINATE);
1229 primary_domain = tmp ? tmp : "";
1231 DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
1232 native_os, native_lanman, primary_domain));
1234 if ( ra_type == RA_WIN2K ) {
1235 /* Vista sets neither the OS or lanman strings */
1237 if ( !strlen(native_os) && !strlen(native_lanman) )
1238 set_remote_arch(RA_VISTA);
1240 /* Windows 2003 doesn't set the native lanman string,
1241 but does set primary domain which is a bug I think */
1243 if ( !strlen(native_lanman) ) {
1244 ra_lanman_string( primary_domain );
1245 } else {
1246 ra_lanman_string( native_lanman );
1250 /* Did we get a valid vuid ? */
1251 if (!is_partial_auth_vuid(sconn, vuid)) {
1252 /* No, then try and see if this is an intermediate sessionsetup
1253 * for a large SPNEGO packet. */
1254 struct pending_auth_data *pad;
1255 pad = get_pending_auth_data(sconn, smbpid);
1256 if (pad) {
1257 DEBUG(10,("reply_sesssetup_and_X_spnego: found "
1258 "pending vuid %u\n",
1259 (unsigned int)pad->vuid ));
1260 vuid = pad->vuid;
1264 /* Do we have a valid vuid now ? */
1265 if (!is_partial_auth_vuid(sconn, vuid)) {
1266 /* No, start a new authentication setup. */
1267 vuid = register_initial_vuid(sconn);
1268 if (vuid == UID_FIELD_INVALID) {
1269 data_blob_free(&blob1);
1270 reply_nterror(req, nt_status_squash(
1271 NT_STATUS_INVALID_PARAMETER));
1272 return;
1276 vuser = get_partial_auth_user_struct(sconn, vuid);
1277 /* This MUST be valid. */
1278 if (!vuser) {
1279 smb_panic("reply_sesssetup_and_X_spnego: invalid vuid.");
1282 /* Large (greater than 4k) SPNEGO blobs are split into multiple
1283 * sessionsetup requests as the Windows limit on the security blob
1284 * field is 4k. Bug #4400. JRA.
1287 status = check_spnego_blob_complete(sconn, smbpid, vuid, &blob1);
1288 if (!NT_STATUS_IS_OK(status)) {
1289 if (!NT_STATUS_EQUAL(status,
1290 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1291 /* Real error - kill the intermediate vuid */
1292 invalidate_vuid(sconn, vuid);
1294 data_blob_free(&blob1);
1295 reply_nterror(req, nt_status_squash(status));
1296 return;
1299 if (blob1.data[0] == ASN1_APPLICATION(0)) {
1301 /* its a negTokenTarg packet */
1303 reply_spnego_negotiate(req, vuid, blob1,
1304 &vuser->auth_ntlmssp_state);
1305 data_blob_free(&blob1);
1306 return;
1309 if (blob1.data[0] == ASN1_CONTEXT(1)) {
1311 /* its a auth packet */
1313 reply_spnego_auth(req, vuid, blob1,
1314 &vuser->auth_ntlmssp_state);
1315 data_blob_free(&blob1);
1316 return;
1319 if (strncmp((char *)(blob1.data), "NTLMSSP", 7) == 0) {
1320 DATA_BLOB chal;
1322 if (!vuser->auth_ntlmssp_state) {
1323 status = auth_ntlmssp_start(&vuser->auth_ntlmssp_state);
1324 if (!NT_STATUS_IS_OK(status)) {
1325 /* Kill the intermediate vuid */
1326 invalidate_vuid(sconn, vuid);
1327 data_blob_free(&blob1);
1328 reply_nterror(req, nt_status_squash(status));
1329 return;
1333 status = auth_ntlmssp_update(vuser->auth_ntlmssp_state,
1334 blob1, &chal);
1336 data_blob_free(&blob1);
1338 reply_spnego_ntlmssp(req, vuid,
1339 &vuser->auth_ntlmssp_state,
1340 &chal, status, OID_NTLMSSP, false);
1341 data_blob_free(&chal);
1342 return;
1345 /* what sort of packet is this? */
1346 DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
1348 data_blob_free(&blob1);
1350 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1353 /****************************************************************************
1354 On new VC == 0, shutdown *all* old connections and users.
1355 It seems that only NT4.x does this. At W2K and above (XP etc.).
1356 a new session setup with VC==0 is ignored.
1357 ****************************************************************************/
1359 static int shutdown_other_smbds(const struct connections_key *key,
1360 const struct connections_data *crec,
1361 void *private_data)
1363 const char *ip = (const char *)private_data;
1365 if (!process_exists(crec->pid)) {
1366 return 0;
1369 if (procid_is_me(&crec->pid)) {
1370 return 0;
1373 if (strcmp(ip, crec->addr) != 0) {
1374 return 0;
1377 DEBUG(0,("shutdown_other_smbds: shutting down pid %u "
1378 "(IP %s)\n", (unsigned int)procid_to_pid(&crec->pid), ip));
1380 messaging_send(smbd_messaging_context(), crec->pid, MSG_SHUTDOWN,
1381 &data_blob_null);
1382 return 0;
1385 static void setup_new_vc_session(void)
1387 char addr[INET6_ADDRSTRLEN];
1389 DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x "
1390 "compatible we would close all old resources.\n"));
1391 #if 0
1392 conn_close_all();
1393 invalidate_all_vuids();
1394 #endif
1395 if (lp_reset_on_zero_vc()) {
1396 connections_forall_read(shutdown_other_smbds,
1397 CONST_DISCARD(void *,
1398 client_addr(get_client_fd(),addr,sizeof(addr))));
1402 /****************************************************************************
1403 Reply to a session setup command.
1404 ****************************************************************************/
1406 void reply_sesssetup_and_X(struct smb_request *req)
1408 int sess_vuid;
1409 int smb_bufsize;
1410 DATA_BLOB lm_resp;
1411 DATA_BLOB nt_resp;
1412 DATA_BLOB plaintext_password;
1413 char *tmp;
1414 const char *user;
1415 fstring sub_user; /* Sainitised username for substituion */
1416 const char *domain;
1417 const char *native_os;
1418 const char *native_lanman;
1419 const char *primary_domain;
1420 struct auth_usersupplied_info *user_info = NULL;
1421 struct auth_serversupplied_info *server_info = NULL;
1422 uint16 smb_flag2 = req->flags2;
1424 NTSTATUS nt_status;
1425 struct smbd_server_connection *sconn = smbd_server_conn;
1427 bool doencrypt = sconn->smb1.negprot.encrypted_passwords;
1429 START_PROFILE(SMBsesssetupX);
1431 ZERO_STRUCT(lm_resp);
1432 ZERO_STRUCT(nt_resp);
1433 ZERO_STRUCT(plaintext_password);
1435 DEBUG(3,("wct=%d flg2=0x%x\n", req->wct, req->flags2));
1437 /* a SPNEGO session setup has 12 command words, whereas a normal
1438 NT1 session setup has 13. See the cifs spec. */
1439 if (req->wct == 12 &&
1440 (req->flags2 & FLAGS2_EXTENDED_SECURITY)) {
1442 if (!sconn->smb1.negprot.spnego) {
1443 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt "
1444 "at SPNEGO session setup when it was not "
1445 "negotiated.\n"));
1446 reply_nterror(req, nt_status_squash(
1447 NT_STATUS_LOGON_FAILURE));
1448 END_PROFILE(SMBsesssetupX);
1449 return;
1452 if (SVAL(req->vwv+4, 0) == 0) {
1453 setup_new_vc_session();
1456 reply_sesssetup_and_X_spnego(req);
1457 END_PROFILE(SMBsesssetupX);
1458 return;
1461 smb_bufsize = SVAL(req->vwv+2, 0);
1463 if (get_Protocol() < PROTOCOL_NT1) {
1464 uint16 passlen1 = SVAL(req->vwv+7, 0);
1466 /* Never do NT status codes with protocols before NT1 as we
1467 * don't get client caps. */
1468 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1470 if ((passlen1 > MAX_PASS_LEN) || (passlen1 > req->buflen)) {
1471 reply_nterror(req, nt_status_squash(
1472 NT_STATUS_INVALID_PARAMETER));
1473 END_PROFILE(SMBsesssetupX);
1474 return;
1477 if (doencrypt) {
1478 lm_resp = data_blob(req->buf, passlen1);
1479 } else {
1480 plaintext_password = data_blob(req->buf, passlen1+1);
1481 /* Ensure null termination */
1482 plaintext_password.data[passlen1] = 0;
1485 srvstr_pull_req_talloc(talloc_tos(), req, &tmp,
1486 req->buf + passlen1, STR_TERMINATE);
1487 user = tmp ? tmp : "";
1489 domain = "";
1491 } else {
1492 uint16 passlen1 = SVAL(req->vwv+7, 0);
1493 uint16 passlen2 = SVAL(req->vwv+8, 0);
1494 enum remote_arch_types ra_type = get_remote_arch();
1495 const uint8_t *p = req->buf;
1496 const uint8_t *save_p = req->buf;
1497 uint16 byte_count;
1500 if(global_client_caps == 0) {
1501 global_client_caps = IVAL(req->vwv+11, 0);
1503 if (!(global_client_caps & CAP_STATUS32)) {
1504 remove_from_common_flags2(
1505 FLAGS2_32_BIT_ERROR_CODES);
1508 /* client_caps is used as final determination if
1509 * client is NT or Win95. This is needed to return
1510 * the correct error codes in some circumstances.
1513 if(ra_type == RA_WINNT || ra_type == RA_WIN2K ||
1514 ra_type == RA_WIN95) {
1515 if(!(global_client_caps & (CAP_NT_SMBS|
1516 CAP_STATUS32))) {
1517 set_remote_arch( RA_WIN95);
1522 if (!doencrypt) {
1523 /* both Win95 and WinNT stuff up the password
1524 * lengths for non-encrypting systems. Uggh.
1526 if passlen1==24 its a win95 system, and its setting
1527 the password length incorrectly. Luckily it still
1528 works with the default code because Win95 will null
1529 terminate the password anyway
1531 if passlen1>0 and passlen2>0 then maybe its a NT box
1532 and its setting passlen2 to some random value which
1533 really stuffs things up. we need to fix that one. */
1535 if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 &&
1536 passlen2 != 1) {
1537 passlen2 = 0;
1541 /* check for nasty tricks */
1542 if (passlen1 > MAX_PASS_LEN
1543 || passlen1 > smbreq_bufrem(req, p)) {
1544 reply_nterror(req, nt_status_squash(
1545 NT_STATUS_INVALID_PARAMETER));
1546 END_PROFILE(SMBsesssetupX);
1547 return;
1550 if (passlen2 > MAX_PASS_LEN
1551 || passlen2 > smbreq_bufrem(req, p+passlen1)) {
1552 reply_nterror(req, nt_status_squash(
1553 NT_STATUS_INVALID_PARAMETER));
1554 END_PROFILE(SMBsesssetupX);
1555 return;
1558 /* Save the lanman2 password and the NT md4 password. */
1560 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
1561 doencrypt = False;
1564 if (doencrypt) {
1565 lm_resp = data_blob(p, passlen1);
1566 nt_resp = data_blob(p+passlen1, passlen2);
1567 } else if (lp_security() != SEC_SHARE) {
1569 * In share level we should ignore any passwords, so
1570 * only read them if we're not.
1572 char *pass = NULL;
1573 bool unic= smb_flag2 & FLAGS2_UNICODE_STRINGS;
1575 if (unic && (passlen2 == 0) && passlen1) {
1576 /* Only a ascii plaintext password was sent. */
1577 (void)srvstr_pull_talloc(talloc_tos(),
1578 req->inbuf,
1579 req->flags2,
1580 &pass,
1581 req->buf,
1582 passlen1,
1583 STR_TERMINATE|STR_ASCII);
1584 } else {
1585 (void)srvstr_pull_talloc(talloc_tos(),
1586 req->inbuf,
1587 req->flags2,
1588 &pass,
1589 req->buf,
1590 unic ? passlen2 : passlen1,
1591 STR_TERMINATE);
1593 if (!pass) {
1594 reply_nterror(req, nt_status_squash(
1595 NT_STATUS_INVALID_PARAMETER));
1596 END_PROFILE(SMBsesssetupX);
1597 return;
1599 plaintext_password = data_blob(pass, strlen(pass)+1);
1602 p += passlen1 + passlen2;
1604 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1605 STR_TERMINATE);
1606 user = tmp ? tmp : "";
1608 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1609 STR_TERMINATE);
1610 domain = tmp ? tmp : "";
1612 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1613 STR_TERMINATE);
1614 native_os = tmp ? tmp : "";
1616 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1617 STR_TERMINATE);
1618 native_lanman = tmp ? tmp : "";
1620 /* not documented or decoded by Ethereal but there is one more
1621 * string in the extra bytes which is the same as the
1622 * PrimaryDomain when using extended security. Windows NT 4
1623 * and 2003 use this string to store the native lanman string.
1624 * Windows 9x does not include a string here at all so we have
1625 * to check if we have any extra bytes left */
1627 byte_count = SVAL(req->vwv+13, 0);
1628 if ( PTR_DIFF(p, save_p) < byte_count) {
1629 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1630 STR_TERMINATE);
1631 primary_domain = tmp ? tmp : "";
1632 } else {
1633 primary_domain = talloc_strdup(talloc_tos(), "null");
1636 DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s] "
1637 "PrimaryDomain=[%s]\n",
1638 domain, native_os, native_lanman, primary_domain));
1640 if ( ra_type == RA_WIN2K ) {
1641 if ( strlen(native_lanman) == 0 )
1642 ra_lanman_string( primary_domain );
1643 else
1644 ra_lanman_string( native_lanman );
1649 if (SVAL(req->vwv+4, 0) == 0) {
1650 setup_new_vc_session();
1653 DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n",
1654 domain, user, get_remote_machine_name()));
1656 if (*user) {
1657 if (sconn->smb1.negprot.spnego) {
1659 /* This has to be here, because this is a perfectly
1660 * valid behaviour for guest logons :-( */
1662 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt "
1663 "at 'normal' session setup after "
1664 "negotiating spnego.\n"));
1665 reply_nterror(req, nt_status_squash(
1666 NT_STATUS_LOGON_FAILURE));
1667 END_PROFILE(SMBsesssetupX);
1668 return;
1670 fstrcpy(sub_user, user);
1671 } else {
1672 fstrcpy(sub_user, lp_guestaccount());
1675 sub_set_smb_name(sub_user);
1677 reload_services(True);
1679 if (lp_security() == SEC_SHARE) {
1680 /* In share level we should ignore any passwords */
1682 data_blob_free(&lm_resp);
1683 data_blob_free(&nt_resp);
1684 data_blob_clear_free(&plaintext_password);
1686 map_username(sconn, sub_user);
1687 add_session_user(sconn, sub_user);
1688 add_session_workgroup(sconn, domain);
1689 /* Then force it to null for the benfit of the code below */
1690 user = "";
1693 if (!*user) {
1695 nt_status = check_guest_password(&server_info);
1697 } else if (doencrypt) {
1698 struct auth_context *negprot_auth_context = NULL;
1699 negprot_auth_context = sconn->smb1.negprot.auth_context;
1700 if (!negprot_auth_context) {
1701 DEBUG(0, ("reply_sesssetup_and_X: Attempted encrypted "
1702 "session setup without negprot denied!\n"));
1703 reply_nterror(req, nt_status_squash(
1704 NT_STATUS_LOGON_FAILURE));
1705 END_PROFILE(SMBsesssetupX);
1706 return;
1708 nt_status = make_user_info_for_reply_enc(&user_info, user,
1709 domain,
1710 lm_resp, nt_resp);
1711 if (NT_STATUS_IS_OK(nt_status)) {
1712 nt_status = negprot_auth_context->check_ntlm_password(
1713 negprot_auth_context,
1714 user_info,
1715 &server_info);
1717 } else {
1718 struct auth_context *plaintext_auth_context = NULL;
1720 nt_status = make_auth_context_subsystem(
1721 &plaintext_auth_context);
1723 if (NT_STATUS_IS_OK(nt_status)) {
1724 uint8_t chal[8];
1726 plaintext_auth_context->get_ntlm_challenge(
1727 plaintext_auth_context, chal);
1729 if (!make_user_info_for_reply(&user_info,
1730 user, domain, chal,
1731 plaintext_password)) {
1732 nt_status = NT_STATUS_NO_MEMORY;
1735 if (NT_STATUS_IS_OK(nt_status)) {
1736 nt_status = plaintext_auth_context->check_ntlm_password(
1737 plaintext_auth_context,
1738 user_info,
1739 &server_info);
1741 (plaintext_auth_context->free)(
1742 &plaintext_auth_context);
1747 free_user_info(&user_info);
1749 if (!NT_STATUS_IS_OK(nt_status)) {
1750 nt_status = do_map_to_guest(nt_status, &server_info,
1751 user, domain);
1754 if (!NT_STATUS_IS_OK(nt_status)) {
1755 data_blob_free(&nt_resp);
1756 data_blob_free(&lm_resp);
1757 data_blob_clear_free(&plaintext_password);
1758 reply_nterror(req, nt_status_squash(nt_status));
1759 END_PROFILE(SMBsesssetupX);
1760 return;
1763 /* Ensure we can't possible take a code path leading to a
1764 * null defref. */
1765 if (!server_info) {
1766 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1767 END_PROFILE(SMBsesssetupX);
1768 return;
1771 if (!server_info->ptok) {
1772 nt_status = create_local_token(server_info);
1774 if (!NT_STATUS_IS_OK(nt_status)) {
1775 DEBUG(10, ("create_local_token failed: %s\n",
1776 nt_errstr(nt_status)));
1777 data_blob_free(&nt_resp);
1778 data_blob_free(&lm_resp);
1779 data_blob_clear_free(&plaintext_password);
1780 reply_nterror(req, nt_status_squash(nt_status));
1781 END_PROFILE(SMBsesssetupX);
1782 return;
1786 data_blob_clear_free(&plaintext_password);
1788 /* it's ok - setup a reply */
1789 reply_outbuf(req, 3, 0);
1790 if (get_Protocol() >= PROTOCOL_NT1) {
1791 push_signature(&req->outbuf);
1792 /* perhaps grab OS version here?? */
1795 if (server_info->guest) {
1796 SSVAL(req->outbuf,smb_vwv2,1);
1799 /* register the name and uid as being validated, so further connections
1800 to a uid can get through without a password, on the same VC */
1802 if (lp_security() == SEC_SHARE) {
1803 sess_vuid = UID_FIELD_INVALID;
1804 TALLOC_FREE(server_info);
1805 } else {
1806 /* Ignore the initial vuid. */
1807 sess_vuid = register_initial_vuid(sconn);
1808 if (sess_vuid == UID_FIELD_INVALID) {
1809 data_blob_free(&nt_resp);
1810 data_blob_free(&lm_resp);
1811 reply_nterror(req, nt_status_squash(
1812 NT_STATUS_LOGON_FAILURE));
1813 END_PROFILE(SMBsesssetupX);
1814 return;
1816 /* register_existing_vuid keeps the server info */
1817 sess_vuid = register_existing_vuid(sconn, sess_vuid,
1818 server_info,
1819 nt_resp.data ? nt_resp : lm_resp,
1820 sub_user);
1821 if (sess_vuid == UID_FIELD_INVALID) {
1822 data_blob_free(&nt_resp);
1823 data_blob_free(&lm_resp);
1824 reply_nterror(req, nt_status_squash(
1825 NT_STATUS_LOGON_FAILURE));
1826 END_PROFILE(SMBsesssetupX);
1827 return;
1830 /* current_user_info is changed on new vuid */
1831 reload_services( True );
1834 data_blob_free(&nt_resp);
1835 data_blob_free(&lm_resp);
1837 SSVAL(req->outbuf,smb_uid,sess_vuid);
1838 SSVAL(req->inbuf,smb_uid,sess_vuid);
1839 req->vuid = sess_vuid;
1841 if (!sconn->smb1.sessions.done_sesssetup) {
1842 sconn->smb1.sessions.max_send =
1843 MIN(sconn->smb1.sessions.max_send,smb_bufsize);
1845 sconn->smb1.sessions.done_sesssetup = true;
1847 END_PROFILE(SMBsesssetupX);
1848 chain_reply(req);
1849 return;