libcli/cldap: fix memory/resource leak
[Samba/gbeck.git] / source3 / smbd / sesssetup.c
blobe8878a29ab32f9a18c2b2c77835a7f4e32820cae
1 /*
2 Unix SMB/CIFS implementation.
3 handle SMBsessionsetup
4 Copyright (C) Andrew Tridgell 1998-2001
5 Copyright (C) Andrew Bartlett 2001
6 Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002
7 Copyright (C) Luke Howard 2003
8 Copyright (C) Volker Lendecke 2007
9 Copyright (C) Jeremy Allison 2007
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 3 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "includes.h"
26 #include "smbd/globals.h"
28 extern enum protocol_types Protocol;
31 on a logon error possibly map the error to success if "map to guest"
32 is set approriately
34 static NTSTATUS do_map_to_guest(NTSTATUS status,
35 auth_serversupplied_info **server_info,
36 const char *user, const char *domain)
38 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
39 if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) ||
40 (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) {
41 DEBUG(3,("No such user %s [%s] - using guest account\n",
42 user, domain));
43 status = make_server_info_guest(NULL, server_info);
47 if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
48 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) {
49 DEBUG(3,("Registered username %s for guest access\n",
50 user));
51 status = make_server_info_guest(NULL, server_info);
55 return status;
58 /****************************************************************************
59 Add the standard 'Samba' signature to the end of the session setup.
60 ****************************************************************************/
62 static int push_signature(uint8 **outbuf)
64 char *lanman;
65 int result, tmp;
67 result = 0;
69 tmp = message_push_string(outbuf, "Unix", STR_TERMINATE);
71 if (tmp == -1) return -1;
72 result += tmp;
74 if (asprintf(&lanman, "Samba %s", samba_version_string()) != -1) {
75 tmp = message_push_string(outbuf, lanman, STR_TERMINATE);
76 SAFE_FREE(lanman);
78 else {
79 tmp = message_push_string(outbuf, "Samba", STR_TERMINATE);
82 if (tmp == -1) return -1;
83 result += tmp;
85 tmp = message_push_string(outbuf, lp_workgroup(), STR_TERMINATE);
87 if (tmp == -1) return -1;
88 result += tmp;
90 return result;
93 /****************************************************************************
94 Send a security blob via a session setup reply.
95 ****************************************************************************/
97 static void reply_sesssetup_blob(struct smb_request *req,
98 DATA_BLOB blob,
99 NTSTATUS nt_status)
101 if (!NT_STATUS_IS_OK(nt_status) &&
102 !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
103 reply_nterror(req, nt_status_squash(nt_status));
104 return;
107 nt_status = nt_status_squash(nt_status);
108 SIVAL(req->outbuf, smb_rcls, NT_STATUS_V(nt_status));
109 SSVAL(req->outbuf, smb_vwv0, 0xFF); /* no chaining possible */
110 SSVAL(req->outbuf, smb_vwv3, blob.length);
112 if ((message_push_blob(&req->outbuf, blob) == -1)
113 || (push_signature(&req->outbuf) == -1)) {
114 reply_nterror(req, NT_STATUS_NO_MEMORY);
118 /****************************************************************************
119 Do a 'guest' logon, getting back the
120 ****************************************************************************/
122 static NTSTATUS check_guest_password(auth_serversupplied_info **server_info)
124 struct auth_context *auth_context;
125 auth_usersupplied_info *user_info = NULL;
127 NTSTATUS nt_status;
128 unsigned char chal[8];
130 ZERO_STRUCT(chal);
132 DEBUG(3,("Got anonymous request\n"));
134 if (!NT_STATUS_IS_OK(nt_status = make_auth_context_fixed(&auth_context,
135 chal))) {
136 return nt_status;
139 if (!make_user_info_guest(&user_info)) {
140 (auth_context->free)(&auth_context);
141 return NT_STATUS_NO_MEMORY;
144 nt_status = auth_context->check_ntlm_password(auth_context,
145 user_info,
146 server_info);
147 (auth_context->free)(&auth_context);
148 free_user_info(&user_info);
149 return nt_status;
153 #ifdef HAVE_KRB5
155 #if 0
156 /* Experiment that failed. See "only happens with a KDC" comment below. */
157 /****************************************************************************
158 Cerate a clock skew error blob for a Windows client.
159 ****************************************************************************/
161 static bool make_krb5_skew_error(DATA_BLOB *pblob_out)
163 krb5_context context = NULL;
164 krb5_error_code kerr = 0;
165 krb5_data reply;
166 krb5_principal host_princ = NULL;
167 char *host_princ_s = NULL;
168 bool ret = False;
170 *pblob_out = data_blob_null;
172 initialize_krb5_error_table();
173 kerr = krb5_init_context(&context);
174 if (kerr) {
175 return False;
177 /* Create server principal. */
178 asprintf(&host_princ_s, "%s$@%s", global_myname(), lp_realm());
179 if (!host_princ_s) {
180 goto out;
182 strlower_m(host_princ_s);
184 kerr = smb_krb5_parse_name(context, host_princ_s, &host_princ);
185 if (kerr) {
186 DEBUG(10,("make_krb5_skew_error: smb_krb5_parse_name failed "
187 "for name %s: Error %s\n",
188 host_princ_s, error_message(kerr) ));
189 goto out;
192 kerr = smb_krb5_mk_error(context, KRB5KRB_AP_ERR_SKEW,
193 host_princ, &reply);
194 if (kerr) {
195 DEBUG(10,("make_krb5_skew_error: smb_krb5_mk_error "
196 "failed: Error %s\n",
197 error_message(kerr) ));
198 goto out;
201 *pblob_out = data_blob(reply.data, reply.length);
202 kerberos_free_data_contents(context,&reply);
203 ret = True;
205 out:
207 if (host_princ_s) {
208 SAFE_FREE(host_princ_s);
210 if (host_princ) {
211 krb5_free_principal(context, host_princ);
213 krb5_free_context(context);
214 return ret;
216 #endif
218 /****************************************************************************
219 Reply to a session setup spnego negotiate packet for kerberos.
220 ****************************************************************************/
222 static void reply_spnego_kerberos(struct smb_request *req,
223 DATA_BLOB *secblob,
224 const char *mechOID,
225 uint16 vuid,
226 bool *p_invalidate_vuid)
228 TALLOC_CTX *mem_ctx;
229 DATA_BLOB ticket;
230 char *client, *p, *domain;
231 fstring netbios_domain_name;
232 struct passwd *pw;
233 fstring user;
234 int sess_vuid = req->vuid;
235 NTSTATUS ret = NT_STATUS_OK;
236 struct PAC_DATA *pac_data = NULL;
237 DATA_BLOB ap_rep, ap_rep_wrapped, response;
238 auth_serversupplied_info *server_info = NULL;
239 DATA_BLOB session_key = data_blob_null;
240 uint8 tok_id[2];
241 DATA_BLOB nullblob = data_blob_null;
242 fstring real_username;
243 bool map_domainuser_to_guest = False;
244 bool username_was_mapped;
245 struct PAC_LOGON_INFO *logon_info = NULL;
247 ZERO_STRUCT(ticket);
248 ZERO_STRUCT(ap_rep);
249 ZERO_STRUCT(ap_rep_wrapped);
250 ZERO_STRUCT(response);
252 /* Normally we will always invalidate the intermediate vuid. */
253 *p_invalidate_vuid = True;
255 mem_ctx = talloc_init("reply_spnego_kerberos");
256 if (mem_ctx == NULL) {
257 reply_nterror(req, nt_status_squash(NT_STATUS_NO_MEMORY));
258 return;
261 if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) {
262 talloc_destroy(mem_ctx);
263 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
264 return;
267 ret = ads_verify_ticket(mem_ctx, lp_realm(), 0, &ticket,
268 &client, &pac_data, &ap_rep,
269 &session_key, True);
271 data_blob_free(&ticket);
273 if (!NT_STATUS_IS_OK(ret)) {
274 #if 0
275 /* Experiment that failed.
276 * See "only happens with a KDC" comment below. */
278 if (NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
281 * Windows in this case returns
282 * NT_STATUS_MORE_PROCESSING_REQUIRED
283 * with a negTokenTarg blob containing an krb5_error
284 * struct ASN1 encoded containing KRB5KRB_AP_ERR_SKEW.
285 * The client then fixes its clock and continues rather
286 * than giving an error. JRA.
287 * -- Looks like this only happens with a KDC. JRA.
290 bool ok = make_krb5_skew_error(&ap_rep);
291 if (!ok) {
292 talloc_destroy(mem_ctx);
293 return ERROR_NT(nt_status_squash(
294 NT_STATUS_LOGON_FAILURE));
296 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep,
297 TOK_ID_KRB_ERROR);
298 response = spnego_gen_auth_response(&ap_rep_wrapped,
299 ret, OID_KERBEROS5_OLD);
300 reply_sesssetup_blob(conn, inbuf, outbuf, response,
301 NT_STATUS_MORE_PROCESSING_REQUIRED);
304 * In this one case we don't invalidate the
305 * intermediate vuid as we're expecting the client
306 * to re-use it for the next sessionsetupX packet. JRA.
309 *p_invalidate_vuid = False;
311 data_blob_free(&ap_rep);
312 data_blob_free(&ap_rep_wrapped);
313 data_blob_free(&response);
314 talloc_destroy(mem_ctx);
315 return -1; /* already replied */
317 #else
318 if (!NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
319 ret = NT_STATUS_LOGON_FAILURE;
321 #endif
322 DEBUG(1,("Failed to verify incoming ticket with error %s!\n",
323 nt_errstr(ret)));
324 talloc_destroy(mem_ctx);
325 reply_nterror(req, nt_status_squash(ret));
326 return;
329 DEBUG(3,("Ticket name is [%s]\n", client));
331 p = strchr_m(client, '@');
332 if (!p) {
333 DEBUG(3,("Doesn't look like a valid principal\n"));
334 data_blob_free(&ap_rep);
335 data_blob_free(&session_key);
336 SAFE_FREE(client);
337 talloc_destroy(mem_ctx);
338 reply_nterror(req,nt_status_squash(NT_STATUS_LOGON_FAILURE));
339 return;
342 *p = 0;
344 /* save the PAC data if we have it */
346 if (pac_data) {
347 logon_info = get_logon_info_from_pac(pac_data);
348 if (logon_info) {
349 netsamlogon_cache_store( client, &logon_info->info3 );
353 if (!strequal(p+1, lp_realm())) {
354 DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1));
355 if (!lp_allow_trusted_domains()) {
356 data_blob_free(&ap_rep);
357 data_blob_free(&session_key);
358 SAFE_FREE(client);
359 talloc_destroy(mem_ctx);
360 reply_nterror(req, nt_status_squash(
361 NT_STATUS_LOGON_FAILURE));
362 return;
366 /* this gives a fully qualified user name (ie. with full realm).
367 that leads to very long usernames, but what else can we do? */
369 domain = p+1;
371 if (logon_info && logon_info->info3.base.domain.string) {
372 fstrcpy(netbios_domain_name,
373 logon_info->info3.base.domain.string);
374 domain = netbios_domain_name;
375 DEBUG(10, ("Mapped to [%s] (using PAC)\n", domain));
377 } else {
379 /* If we have winbind running, we can (and must) shorten the
380 username by using the short netbios name. Otherwise we will
381 have inconsistent user names. With Kerberos, we get the
382 fully qualified realm, with ntlmssp we get the short
383 name. And even w2k3 does use ntlmssp if you for example
384 connect to an ip address. */
386 wbcErr wbc_status;
387 struct wbcDomainInfo *info = NULL;
389 DEBUG(10, ("Mapping [%s] to short name\n", domain));
391 wbc_status = wbcDomainInfo(domain, &info);
393 if (WBC_ERROR_IS_OK(wbc_status)) {
395 fstrcpy(netbios_domain_name,
396 info->short_name);
398 wbcFreeMemory(info);
399 domain = netbios_domain_name;
400 DEBUG(10, ("Mapped to [%s] (using Winbind)\n", domain));
401 } else {
402 DEBUG(3, ("Could not find short name: %s\n",
403 wbcErrorString(wbc_status)));
407 fstr_sprintf(user, "%s%c%s", domain, *lp_winbind_separator(), client);
409 /* lookup the passwd struct, create a new user if necessary */
411 username_was_mapped = map_username( user );
413 pw = smb_getpwnam( mem_ctx, user, real_username, True );
415 if (pw) {
416 /* if a real user check pam account restrictions */
417 /* only really perfomed if "obey pam restriction" is true */
418 /* do this before an eventual mapping to guest occurs */
419 ret = smb_pam_accountcheck(pw->pw_name);
420 if ( !NT_STATUS_IS_OK(ret)) {
421 DEBUG(1,("PAM account restriction "
422 "prevents user login\n"));
423 data_blob_free(&ap_rep);
424 data_blob_free(&session_key);
425 TALLOC_FREE(mem_ctx);
426 reply_nterror(req, nt_status_squash(ret));
427 return;
431 if (!pw) {
433 /* this was originally the behavior of Samba 2.2, if a user
434 did not have a local uid but has been authenticated, then
435 map them to a guest account */
437 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID){
438 map_domainuser_to_guest = True;
439 fstrcpy(user,lp_guestaccount());
440 pw = smb_getpwnam( mem_ctx, user, real_username, True );
443 /* extra sanity check that the guest account is valid */
445 if ( !pw ) {
446 DEBUG(1,("Username %s is invalid on this system\n",
447 user));
448 SAFE_FREE(client);
449 data_blob_free(&ap_rep);
450 data_blob_free(&session_key);
451 TALLOC_FREE(mem_ctx);
452 reply_nterror(req, nt_status_squash(
453 NT_STATUS_LOGON_FAILURE));
454 return;
458 /* setup the string used by %U */
460 sub_set_smb_name( real_username );
461 reload_services(True);
463 if ( map_domainuser_to_guest ) {
464 make_server_info_guest(NULL, &server_info);
465 } else if (logon_info) {
466 /* pass the unmapped username here since map_username()
467 will be called again from inside make_server_info_info3() */
469 ret = make_server_info_info3(mem_ctx, client, domain,
470 &server_info, &logon_info->info3);
471 if ( !NT_STATUS_IS_OK(ret) ) {
472 DEBUG(1,("make_server_info_info3 failed: %s!\n",
473 nt_errstr(ret)));
474 SAFE_FREE(client);
475 data_blob_free(&ap_rep);
476 data_blob_free(&session_key);
477 TALLOC_FREE(mem_ctx);
478 reply_nterror(req, nt_status_squash(ret));
479 return;
482 } else {
483 ret = make_server_info_pw(&server_info, real_username, pw);
485 if ( !NT_STATUS_IS_OK(ret) ) {
486 DEBUG(1,("make_server_info_pw failed: %s!\n",
487 nt_errstr(ret)));
488 SAFE_FREE(client);
489 data_blob_free(&ap_rep);
490 data_blob_free(&session_key);
491 TALLOC_FREE(mem_ctx);
492 reply_nterror(req, nt_status_squash(ret));
493 return;
496 /* make_server_info_pw does not set the domain. Without this
497 * we end up with the local netbios name in substitutions for
498 * %D. */
500 if (server_info->sam_account != NULL) {
501 pdb_set_domain(server_info->sam_account,
502 domain, PDB_SET);
506 server_info->nss_token |= username_was_mapped;
508 /* we need to build the token for the user. make_server_info_guest()
509 already does this */
511 if ( !server_info->ptok ) {
512 ret = create_local_token( server_info );
513 if ( !NT_STATUS_IS_OK(ret) ) {
514 DEBUG(10,("failed to create local token: %s\n",
515 nt_errstr(ret)));
516 SAFE_FREE(client);
517 data_blob_free(&ap_rep);
518 data_blob_free(&session_key);
519 TALLOC_FREE( mem_ctx );
520 TALLOC_FREE( server_info );
521 reply_nterror(req, nt_status_squash(ret));
522 return;
526 if (!is_partial_auth_vuid(sess_vuid)) {
527 sess_vuid = register_initial_vuid();
530 data_blob_free(&server_info->user_session_key);
531 server_info->user_session_key = session_key;
532 session_key = data_blob_null;
534 /* register_existing_vuid keeps the server info */
535 /* register_existing_vuid takes ownership of session_key on success,
536 * no need to free after this on success. A better interface would copy
537 * it.... */
539 sess_vuid = register_existing_vuid(sess_vuid,
540 server_info,
541 nullblob,
542 client);
544 SAFE_FREE(client);
546 reply_outbuf(req, 4, 0);
547 SSVAL(req->outbuf,smb_uid,sess_vuid);
549 if (sess_vuid == UID_FIELD_INVALID ) {
550 ret = NT_STATUS_LOGON_FAILURE;
551 } else {
552 /* current_user_info is changed on new vuid */
553 reload_services( True );
555 SSVAL(req->outbuf, smb_vwv3, 0);
557 if (server_info->guest) {
558 SSVAL(req->outbuf,smb_vwv2,1);
561 SSVAL(req->outbuf, smb_uid, sess_vuid);
563 /* Successful logon. Keep this vuid. */
564 *p_invalidate_vuid = False;
567 /* wrap that up in a nice GSS-API wrapping */
568 if (NT_STATUS_IS_OK(ret)) {
569 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep,
570 TOK_ID_KRB_AP_REP);
571 } else {
572 ap_rep_wrapped = data_blob_null;
574 response = spnego_gen_auth_response(&ap_rep_wrapped, ret,
575 mechOID);
576 reply_sesssetup_blob(req, response, ret);
578 data_blob_free(&ap_rep);
579 data_blob_free(&ap_rep_wrapped);
580 data_blob_free(&response);
581 TALLOC_FREE(mem_ctx);
584 #endif
586 /****************************************************************************
587 Send a session setup reply, wrapped in SPNEGO.
588 Get vuid and check first.
589 End the NTLMSSP exchange context if we are OK/complete fail
590 This should be split into two functions, one to handle each
591 leg of the NTLM auth steps.
592 ***************************************************************************/
594 static void reply_spnego_ntlmssp(struct smb_request *req,
595 uint16 vuid,
596 AUTH_NTLMSSP_STATE **auth_ntlmssp_state,
597 DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status,
598 const char *OID,
599 bool wrap)
601 DATA_BLOB response;
602 struct auth_serversupplied_info *server_info = NULL;
604 if (NT_STATUS_IS_OK(nt_status)) {
605 server_info = (*auth_ntlmssp_state)->server_info;
606 } else {
607 nt_status = do_map_to_guest(nt_status,
608 &server_info,
609 (*auth_ntlmssp_state)->ntlmssp_state->user,
610 (*auth_ntlmssp_state)->ntlmssp_state->domain);
613 reply_outbuf(req, 4, 0);
615 SSVAL(req->outbuf, smb_uid, vuid);
617 if (NT_STATUS_IS_OK(nt_status)) {
618 DATA_BLOB nullblob = data_blob_null;
620 if (!is_partial_auth_vuid(vuid)) {
621 nt_status = NT_STATUS_LOGON_FAILURE;
622 goto out;
625 data_blob_free(&server_info->user_session_key);
626 server_info->user_session_key =
627 data_blob_talloc(
628 server_info,
629 (*auth_ntlmssp_state)->ntlmssp_state->session_key.data,
630 (*auth_ntlmssp_state)->ntlmssp_state->session_key.length);
632 /* register_existing_vuid keeps the server info */
633 if (register_existing_vuid(vuid,
634 server_info, nullblob,
635 (*auth_ntlmssp_state)->ntlmssp_state->user) !=
636 vuid) {
637 nt_status = NT_STATUS_LOGON_FAILURE;
638 goto out;
641 (*auth_ntlmssp_state)->server_info = NULL;
643 /* current_user_info is changed on new vuid */
644 reload_services( True );
646 SSVAL(req->outbuf, smb_vwv3, 0);
648 if (server_info->guest) {
649 SSVAL(req->outbuf,smb_vwv2,1);
653 out:
655 if (wrap) {
656 response = spnego_gen_auth_response(ntlmssp_blob,
657 nt_status, OID);
658 } else {
659 response = *ntlmssp_blob;
662 reply_sesssetup_blob(req, response, nt_status);
663 if (wrap) {
664 data_blob_free(&response);
667 /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
668 and the other end, that we are not finished yet. */
670 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
671 /* NB. This is *NOT* an error case. JRA */
672 auth_ntlmssp_end(auth_ntlmssp_state);
673 if (!NT_STATUS_IS_OK(nt_status)) {
674 /* Kill the intermediate vuid */
675 invalidate_vuid(vuid);
680 /****************************************************************************
681 Is this a krb5 mechanism ?
682 ****************************************************************************/
684 NTSTATUS parse_spnego_mechanisms(DATA_BLOB blob_in,
685 DATA_BLOB *pblob_out,
686 char **kerb_mechOID)
688 char *OIDs[ASN1_MAX_OIDS];
689 int i;
690 NTSTATUS ret = NT_STATUS_OK;
692 *kerb_mechOID = NULL;
694 /* parse out the OIDs and the first sec blob */
695 if (!parse_negTokenTarg(blob_in, OIDs, pblob_out)) {
696 return NT_STATUS_LOGON_FAILURE;
699 /* only look at the first OID for determining the mechToken --
700 according to RFC2478, we should choose the one we want
701 and renegotiate, but i smell a client bug here..
703 Problem observed when connecting to a member (samba box)
704 of an AD domain as a user in a Samba domain. Samba member
705 server sent back krb5/mskrb5/ntlmssp as mechtypes, but the
706 client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an
707 NTLMSSP mechtoken. --jerry */
709 #ifdef HAVE_KRB5
710 if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||
711 strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
712 *kerb_mechOID = SMB_STRDUP(OIDs[0]);
713 if (*kerb_mechOID == NULL) {
714 ret = NT_STATUS_NO_MEMORY;
717 #endif
719 for (i=0;OIDs[i];i++) {
720 DEBUG(5,("parse_spnego_mechanisms: Got OID %s\n", OIDs[i]));
721 talloc_free(OIDs[i]);
723 return ret;
726 /****************************************************************************
727 Fall back from krb5 to NTLMSSP.
728 ****************************************************************************/
730 static void reply_spnego_downgrade_to_ntlmssp(struct smb_request *req,
731 uint16 vuid)
733 DATA_BLOB response;
735 reply_outbuf(req, 4, 0);
736 SSVAL(req->outbuf,smb_uid,vuid);
738 DEBUG(3,("reply_spnego_downgrade_to_ntlmssp: Got krb5 ticket in SPNEGO "
739 "but set to downgrade to NTLMSSP\n"));
741 response = spnego_gen_auth_response(NULL,
742 NT_STATUS_MORE_PROCESSING_REQUIRED,
743 OID_NTLMSSP);
744 reply_sesssetup_blob(req, response, NT_STATUS_MORE_PROCESSING_REQUIRED);
745 data_blob_free(&response);
748 /****************************************************************************
749 Reply to a session setup spnego negotiate packet.
750 ****************************************************************************/
752 static void reply_spnego_negotiate(struct smb_request *req,
753 uint16 vuid,
754 DATA_BLOB blob1,
755 AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
757 DATA_BLOB secblob;
758 DATA_BLOB chal;
759 char *kerb_mech = NULL;
760 NTSTATUS status;
762 status = parse_spnego_mechanisms(blob1, &secblob, &kerb_mech);
763 if (!NT_STATUS_IS_OK(status)) {
764 /* Kill the intermediate vuid */
765 invalidate_vuid(vuid);
766 reply_nterror(req, nt_status_squash(status));
767 return;
770 DEBUG(3,("reply_spnego_negotiate: Got secblob of size %lu\n",
771 (unsigned long)secblob.length));
773 #ifdef HAVE_KRB5
774 if (kerb_mech && ((lp_security()==SEC_ADS) ||
775 USE_KERBEROS_KEYTAB) ) {
776 bool destroy_vuid = True;
777 reply_spnego_kerberos(req, &secblob, kerb_mech,
778 vuid, &destroy_vuid);
779 data_blob_free(&secblob);
780 if (destroy_vuid) {
781 /* Kill the intermediate vuid */
782 invalidate_vuid(vuid);
784 SAFE_FREE(kerb_mech);
785 return;
787 #endif
789 if (*auth_ntlmssp_state) {
790 auth_ntlmssp_end(auth_ntlmssp_state);
793 if (kerb_mech) {
794 data_blob_free(&secblob);
795 /* The mechtoken is a krb5 ticket, but
796 * we need to fall back to NTLM. */
797 reply_spnego_downgrade_to_ntlmssp(req, vuid);
798 SAFE_FREE(kerb_mech);
799 return;
802 status = auth_ntlmssp_start(auth_ntlmssp_state);
803 if (!NT_STATUS_IS_OK(status)) {
804 /* Kill the intermediate vuid */
805 invalidate_vuid(vuid);
806 reply_nterror(req, nt_status_squash(status));
807 return;
810 status = auth_ntlmssp_update(*auth_ntlmssp_state,
811 secblob, &chal);
813 data_blob_free(&secblob);
815 reply_spnego_ntlmssp(req, vuid, auth_ntlmssp_state,
816 &chal, status, OID_NTLMSSP, true);
818 data_blob_free(&chal);
820 /* already replied */
821 return;
824 /****************************************************************************
825 Reply to a session setup spnego auth packet.
826 ****************************************************************************/
828 static void reply_spnego_auth(struct smb_request *req,
829 uint16 vuid,
830 DATA_BLOB blob1,
831 AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
833 DATA_BLOB auth = data_blob_null;
834 DATA_BLOB auth_reply = data_blob_null;
835 DATA_BLOB secblob = data_blob_null;
836 NTSTATUS status = NT_STATUS_LOGON_FAILURE;
838 if (!spnego_parse_auth(blob1, &auth)) {
839 #if 0
840 file_save("auth.dat", blob1.data, blob1.length);
841 #endif
842 /* Kill the intermediate vuid */
843 invalidate_vuid(vuid);
845 reply_nterror(req, nt_status_squash(
846 NT_STATUS_LOGON_FAILURE));
847 return;
850 if (auth.data[0] == ASN1_APPLICATION(0)) {
851 /* Might be a second negTokenTarg packet */
852 char *kerb_mech = NULL;
854 status = parse_spnego_mechanisms(auth, &secblob, &kerb_mech);
856 if (!NT_STATUS_IS_OK(status)) {
857 /* Kill the intermediate vuid */
858 invalidate_vuid(vuid);
859 reply_nterror(req, nt_status_squash(status));
860 return;
863 DEBUG(3,("reply_spnego_auth: Got secblob of size %lu\n",
864 (unsigned long)secblob.length));
865 #ifdef HAVE_KRB5
866 if (kerb_mech && ((lp_security()==SEC_ADS) ||
867 USE_KERBEROS_KEYTAB)) {
868 bool destroy_vuid = True;
869 reply_spnego_kerberos(req, &secblob, kerb_mech,
870 vuid, &destroy_vuid);
871 data_blob_free(&secblob);
872 data_blob_free(&auth);
873 if (destroy_vuid) {
874 /* Kill the intermediate vuid */
875 invalidate_vuid(vuid);
877 SAFE_FREE(kerb_mech);
878 return;
880 #endif
881 /* Can't blunder into NTLMSSP auth if we have
882 * a krb5 ticket. */
884 if (kerb_mech) {
885 /* Kill the intermediate vuid */
886 invalidate_vuid(vuid);
887 DEBUG(3,("reply_spnego_auth: network "
888 "misconfiguration, client sent us a "
889 "krb5 ticket and kerberos security "
890 "not enabled\n"));
891 reply_nterror(req, nt_status_squash(
892 NT_STATUS_LOGON_FAILURE));
893 SAFE_FREE(kerb_mech);
897 /* If we get here it wasn't a negTokenTarg auth packet. */
898 data_blob_free(&secblob);
900 if (!*auth_ntlmssp_state) {
901 status = auth_ntlmssp_start(auth_ntlmssp_state);
902 if (!NT_STATUS_IS_OK(status)) {
903 /* Kill the intermediate vuid */
904 invalidate_vuid(vuid);
905 reply_nterror(req, nt_status_squash(status));
906 return;
910 status = auth_ntlmssp_update(*auth_ntlmssp_state,
911 auth, &auth_reply);
913 data_blob_free(&auth);
915 /* Don't send the mechid as we've already sent this (RFC4178). */
917 reply_spnego_ntlmssp(req, vuid,
918 auth_ntlmssp_state,
919 &auth_reply, status, NULL, true);
921 data_blob_free(&auth_reply);
923 /* and tell smbd that we have already replied to this packet */
924 return;
927 /****************************************************************************
928 Delete an entry on the list.
929 ****************************************************************************/
931 static void delete_partial_auth(struct pending_auth_data *pad)
933 if (!pad) {
934 return;
936 DLIST_REMOVE(pd_list, pad);
937 data_blob_free(&pad->partial_data);
938 SAFE_FREE(pad);
941 /****************************************************************************
942 Search for a partial SPNEGO auth fragment matching an smbpid.
943 ****************************************************************************/
945 static struct pending_auth_data *get_pending_auth_data(uint16 smbpid)
947 struct pending_auth_data *pad;
949 for (pad = pd_list; pad; pad = pad->next) {
950 if (pad->smbpid == smbpid) {
951 break;
954 return pad;
957 /****************************************************************************
958 Check the size of an SPNEGO blob. If we need more return
959 NT_STATUS_MORE_PROCESSING_REQUIRED, else return NT_STATUS_OK. Don't allow
960 the blob to be more than 64k.
961 ****************************************************************************/
963 static NTSTATUS check_spnego_blob_complete(uint16 smbpid, uint16 vuid,
964 DATA_BLOB *pblob)
966 struct pending_auth_data *pad = NULL;
967 ASN1_DATA *data;
968 size_t needed_len = 0;
970 pad = get_pending_auth_data(smbpid);
972 /* Ensure we have some data. */
973 if (pblob->length == 0) {
974 /* Caller can cope. */
975 DEBUG(2,("check_spnego_blob_complete: zero blob length !\n"));
976 delete_partial_auth(pad);
977 return NT_STATUS_OK;
980 /* Were we waiting for more data ? */
981 if (pad) {
982 DATA_BLOB tmp_blob;
983 size_t copy_len = MIN(65536, pblob->length);
985 /* Integer wrap paranoia.... */
987 if (pad->partial_data.length + copy_len <
988 pad->partial_data.length ||
989 pad->partial_data.length + copy_len < copy_len) {
991 DEBUG(2,("check_spnego_blob_complete: integer wrap "
992 "pad->partial_data.length = %u, "
993 "copy_len = %u\n",
994 (unsigned int)pad->partial_data.length,
995 (unsigned int)copy_len ));
997 delete_partial_auth(pad);
998 return NT_STATUS_INVALID_PARAMETER;
1001 DEBUG(10,("check_spnego_blob_complete: "
1002 "pad->partial_data.length = %u, "
1003 "pad->needed_len = %u, "
1004 "copy_len = %u, "
1005 "pblob->length = %u,\n",
1006 (unsigned int)pad->partial_data.length,
1007 (unsigned int)pad->needed_len,
1008 (unsigned int)copy_len,
1009 (unsigned int)pblob->length ));
1011 tmp_blob = data_blob(NULL,
1012 pad->partial_data.length + copy_len);
1014 /* Concatenate the two (up to copy_len) bytes. */
1015 memcpy(tmp_blob.data,
1016 pad->partial_data.data,
1017 pad->partial_data.length);
1018 memcpy(tmp_blob.data + pad->partial_data.length,
1019 pblob->data,
1020 copy_len);
1022 /* Replace the partial data. */
1023 data_blob_free(&pad->partial_data);
1024 pad->partial_data = tmp_blob;
1025 ZERO_STRUCT(tmp_blob);
1027 /* Are we done ? */
1028 if (pblob->length >= pad->needed_len) {
1029 /* Yes, replace pblob. */
1030 data_blob_free(pblob);
1031 *pblob = pad->partial_data;
1032 ZERO_STRUCT(pad->partial_data);
1033 delete_partial_auth(pad);
1034 return NT_STATUS_OK;
1037 /* Still need more data. */
1038 pad->needed_len -= copy_len;
1039 return NT_STATUS_MORE_PROCESSING_REQUIRED;
1042 if ((pblob->data[0] != ASN1_APPLICATION(0)) &&
1043 (pblob->data[0] != ASN1_CONTEXT(1))) {
1044 /* Not something we can determine the
1045 * length of.
1047 return NT_STATUS_OK;
1050 /* This is a new SPNEGO sessionsetup - see if
1051 * the data given in this blob is enough.
1054 data = asn1_init(NULL);
1055 if (data == NULL) {
1056 return NT_STATUS_NO_MEMORY;
1059 asn1_load(data, *pblob);
1060 asn1_start_tag(data, pblob->data[0]);
1061 if (data->has_error || data->nesting == NULL) {
1062 asn1_free(data);
1063 /* Let caller catch. */
1064 return NT_STATUS_OK;
1067 /* Integer wrap paranoia.... */
1069 if (data->nesting->taglen + data->nesting->start < data->nesting->taglen ||
1070 data->nesting->taglen + data->nesting->start < data->nesting->start) {
1072 DEBUG(2,("check_spnego_blob_complete: integer wrap "
1073 "data.nesting->taglen = %u, "
1074 "data.nesting->start = %u\n",
1075 (unsigned int)data->nesting->taglen,
1076 (unsigned int)data->nesting->start ));
1078 asn1_free(data);
1079 return NT_STATUS_INVALID_PARAMETER;
1082 /* Total length of the needed asn1 is the tag length
1083 * plus the current offset. */
1085 needed_len = data->nesting->taglen + data->nesting->start;
1086 asn1_free(data);
1088 DEBUG(10,("check_spnego_blob_complete: needed_len = %u, "
1089 "pblob->length = %u\n",
1090 (unsigned int)needed_len,
1091 (unsigned int)pblob->length ));
1093 if (needed_len <= pblob->length) {
1094 /* Nothing to do - blob is complete. */
1095 return NT_STATUS_OK;
1098 /* Refuse the blob if it's bigger than 64k. */
1099 if (needed_len > 65536) {
1100 DEBUG(2,("check_spnego_blob_complete: needed_len "
1101 "too large (%u)\n",
1102 (unsigned int)needed_len ));
1103 return NT_STATUS_INVALID_PARAMETER;
1106 /* We must store this blob until complete. */
1107 if (!(pad = SMB_MALLOC_P(struct pending_auth_data))) {
1108 return NT_STATUS_NO_MEMORY;
1110 pad->needed_len = needed_len - pblob->length;
1111 pad->partial_data = data_blob(pblob->data, pblob->length);
1112 if (pad->partial_data.data == NULL) {
1113 SAFE_FREE(pad);
1114 return NT_STATUS_NO_MEMORY;
1116 pad->smbpid = smbpid;
1117 pad->vuid = vuid;
1118 DLIST_ADD(pd_list, pad);
1120 return NT_STATUS_MORE_PROCESSING_REQUIRED;
1123 /****************************************************************************
1124 Reply to a session setup command.
1125 conn POINTER CAN BE NULL HERE !
1126 ****************************************************************************/
1128 static void reply_sesssetup_and_X_spnego(struct smb_request *req)
1130 const uint8 *p;
1131 DATA_BLOB blob1;
1132 size_t bufrem;
1133 char *tmp;
1134 const char *native_os;
1135 const char *native_lanman;
1136 const char *primary_domain;
1137 const char *p2;
1138 uint16 data_blob_len = SVAL(req->vwv+7, 0);
1139 enum remote_arch_types ra_type = get_remote_arch();
1140 int vuid = req->vuid;
1141 user_struct *vuser = NULL;
1142 NTSTATUS status = NT_STATUS_OK;
1143 uint16 smbpid = req->smbpid;
1145 DEBUG(3,("Doing spnego session setup\n"));
1147 if (global_client_caps == 0) {
1148 global_client_caps = IVAL(req->vwv+10, 0);
1150 if (!(global_client_caps & CAP_STATUS32)) {
1151 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1156 p = req->buf;
1158 if (data_blob_len == 0) {
1159 /* an invalid request */
1160 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1161 return;
1164 bufrem = smbreq_bufrem(req, p);
1165 /* pull the spnego blob */
1166 blob1 = data_blob(p, MIN(bufrem, data_blob_len));
1168 #if 0
1169 file_save("negotiate.dat", blob1.data, blob1.length);
1170 #endif
1172 p2 = (char *)req->buf + data_blob_len;
1174 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1175 STR_TERMINATE);
1176 native_os = tmp ? tmp : "";
1178 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1179 STR_TERMINATE);
1180 native_lanman = tmp ? tmp : "";
1182 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1183 STR_TERMINATE);
1184 primary_domain = tmp ? tmp : "";
1186 DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
1187 native_os, native_lanman, primary_domain));
1189 if ( ra_type == RA_WIN2K ) {
1190 /* Vista sets neither the OS or lanman strings */
1192 if ( !strlen(native_os) && !strlen(native_lanman) )
1193 set_remote_arch(RA_VISTA);
1195 /* Windows 2003 doesn't set the native lanman string,
1196 but does set primary domain which is a bug I think */
1198 if ( !strlen(native_lanman) ) {
1199 ra_lanman_string( primary_domain );
1200 } else {
1201 ra_lanman_string( native_lanman );
1205 /* Did we get a valid vuid ? */
1206 if (!is_partial_auth_vuid(vuid)) {
1207 /* No, then try and see if this is an intermediate sessionsetup
1208 * for a large SPNEGO packet. */
1209 struct pending_auth_data *pad = get_pending_auth_data(smbpid);
1210 if (pad) {
1211 DEBUG(10,("reply_sesssetup_and_X_spnego: found "
1212 "pending vuid %u\n",
1213 (unsigned int)pad->vuid ));
1214 vuid = pad->vuid;
1218 /* Do we have a valid vuid now ? */
1219 if (!is_partial_auth_vuid(vuid)) {
1220 /* No, start a new authentication setup. */
1221 vuid = register_initial_vuid();
1222 if (vuid == UID_FIELD_INVALID) {
1223 data_blob_free(&blob1);
1224 reply_nterror(req, nt_status_squash(
1225 NT_STATUS_INVALID_PARAMETER));
1226 return;
1230 vuser = get_partial_auth_user_struct(vuid);
1231 /* This MUST be valid. */
1232 if (!vuser) {
1233 smb_panic("reply_sesssetup_and_X_spnego: invalid vuid.");
1236 /* Large (greater than 4k) SPNEGO blobs are split into multiple
1237 * sessionsetup requests as the Windows limit on the security blob
1238 * field is 4k. Bug #4400. JRA.
1241 status = check_spnego_blob_complete(smbpid, vuid, &blob1);
1242 if (!NT_STATUS_IS_OK(status)) {
1243 if (!NT_STATUS_EQUAL(status,
1244 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1245 /* Real error - kill the intermediate vuid */
1246 invalidate_vuid(vuid);
1248 data_blob_free(&blob1);
1249 reply_nterror(req, nt_status_squash(status));
1250 return;
1253 if (blob1.data[0] == ASN1_APPLICATION(0)) {
1255 /* its a negTokenTarg packet */
1257 reply_spnego_negotiate(req, vuid, blob1,
1258 &vuser->auth_ntlmssp_state);
1259 data_blob_free(&blob1);
1260 return;
1263 if (blob1.data[0] == ASN1_CONTEXT(1)) {
1265 /* its a auth packet */
1267 reply_spnego_auth(req, vuid, blob1,
1268 &vuser->auth_ntlmssp_state);
1269 data_blob_free(&blob1);
1270 return;
1273 if (strncmp((char *)(blob1.data), "NTLMSSP", 7) == 0) {
1274 DATA_BLOB chal;
1276 if (!vuser->auth_ntlmssp_state) {
1277 status = auth_ntlmssp_start(&vuser->auth_ntlmssp_state);
1278 if (!NT_STATUS_IS_OK(status)) {
1279 /* Kill the intermediate vuid */
1280 invalidate_vuid(vuid);
1281 data_blob_free(&blob1);
1282 reply_nterror(req, nt_status_squash(status));
1283 return;
1287 status = auth_ntlmssp_update(vuser->auth_ntlmssp_state,
1288 blob1, &chal);
1290 data_blob_free(&blob1);
1292 reply_spnego_ntlmssp(req, vuid,
1293 &vuser->auth_ntlmssp_state,
1294 &chal, status, OID_NTLMSSP, false);
1295 data_blob_free(&chal);
1296 return;
1299 /* what sort of packet is this? */
1300 DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
1302 data_blob_free(&blob1);
1304 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1307 /****************************************************************************
1308 On new VC == 0, shutdown *all* old connections and users.
1309 It seems that only NT4.x does this. At W2K and above (XP etc.).
1310 a new session setup with VC==0 is ignored.
1311 ****************************************************************************/
1313 static int shutdown_other_smbds(struct db_record *rec,
1314 const struct connections_key *key,
1315 const struct connections_data *crec,
1316 void *private_data)
1318 const char *ip = (const char *)private_data;
1320 if (!process_exists(crec->pid)) {
1321 return 0;
1324 if (procid_is_me(&crec->pid)) {
1325 return 0;
1328 if (strcmp(ip, crec->addr) != 0) {
1329 return 0;
1332 DEBUG(0,("shutdown_other_smbds: shutting down pid %u "
1333 "(IP %s)\n", (unsigned int)procid_to_pid(&crec->pid), ip));
1335 messaging_send(smbd_messaging_context(), crec->pid, MSG_SHUTDOWN,
1336 &data_blob_null);
1337 return 0;
1340 static void setup_new_vc_session(void)
1342 char addr[INET6_ADDRSTRLEN];
1344 DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x "
1345 "compatible we would close all old resources.\n"));
1346 #if 0
1347 conn_close_all();
1348 invalidate_all_vuids();
1349 #endif
1350 if (lp_reset_on_zero_vc()) {
1351 connections_forall(shutdown_other_smbds,
1352 CONST_DISCARD(void *,
1353 client_addr(get_client_fd(),addr,sizeof(addr))));
1357 /****************************************************************************
1358 Reply to a session setup command.
1359 ****************************************************************************/
1361 void reply_sesssetup_and_X(struct smb_request *req)
1363 int sess_vuid;
1364 int smb_bufsize;
1365 DATA_BLOB lm_resp;
1366 DATA_BLOB nt_resp;
1367 DATA_BLOB plaintext_password;
1368 char *tmp;
1369 const char *user;
1370 fstring sub_user; /* Sainitised username for substituion */
1371 const char *domain;
1372 const char *native_os;
1373 const char *native_lanman;
1374 const char *primary_domain;
1375 auth_usersupplied_info *user_info = NULL;
1376 auth_serversupplied_info *server_info = NULL;
1377 uint16 smb_flag2 = req->flags2;
1379 NTSTATUS nt_status;
1381 bool doencrypt = global_encrypted_passwords_negotiated;
1383 START_PROFILE(SMBsesssetupX);
1385 ZERO_STRUCT(lm_resp);
1386 ZERO_STRUCT(nt_resp);
1387 ZERO_STRUCT(plaintext_password);
1389 DEBUG(3,("wct=%d flg2=0x%x\n", req->wct, req->flags2));
1391 /* a SPNEGO session setup has 12 command words, whereas a normal
1392 NT1 session setup has 13. See the cifs spec. */
1393 if (req->wct == 12 &&
1394 (req->flags2 & FLAGS2_EXTENDED_SECURITY)) {
1396 if (!global_spnego_negotiated) {
1397 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt "
1398 "at SPNEGO session setup when it was not "
1399 "negotiated.\n"));
1400 reply_nterror(req, nt_status_squash(
1401 NT_STATUS_LOGON_FAILURE));
1402 END_PROFILE(SMBsesssetupX);
1403 return;
1406 if (SVAL(req->vwv+4, 0) == 0) {
1407 setup_new_vc_session();
1410 reply_sesssetup_and_X_spnego(req);
1411 END_PROFILE(SMBsesssetupX);
1412 return;
1415 smb_bufsize = SVAL(req->vwv+2, 0);
1417 if (Protocol < PROTOCOL_NT1) {
1418 uint16 passlen1 = SVAL(req->vwv+7, 0);
1420 /* Never do NT status codes with protocols before NT1 as we
1421 * don't get client caps. */
1422 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1424 if ((passlen1 > MAX_PASS_LEN) || (passlen1 > req->buflen)) {
1425 reply_nterror(req, nt_status_squash(
1426 NT_STATUS_INVALID_PARAMETER));
1427 END_PROFILE(SMBsesssetupX);
1428 return;
1431 if (doencrypt) {
1432 lm_resp = data_blob(req->buf, passlen1);
1433 } else {
1434 plaintext_password = data_blob(req->buf, passlen1+1);
1435 /* Ensure null termination */
1436 plaintext_password.data[passlen1] = 0;
1439 srvstr_pull_req_talloc(talloc_tos(), req, &tmp,
1440 req->buf + passlen1, STR_TERMINATE);
1441 user = tmp ? tmp : "";
1443 domain = "";
1445 } else {
1446 uint16 passlen1 = SVAL(req->vwv+7, 0);
1447 uint16 passlen2 = SVAL(req->vwv+8, 0);
1448 enum remote_arch_types ra_type = get_remote_arch();
1449 const uint8_t *p = req->buf;
1450 const uint8_t *save_p = req->buf;
1451 uint16 byte_count;
1454 if(global_client_caps == 0) {
1455 global_client_caps = IVAL(req->vwv+11, 0);
1457 if (!(global_client_caps & CAP_STATUS32)) {
1458 remove_from_common_flags2(
1459 FLAGS2_32_BIT_ERROR_CODES);
1462 /* client_caps is used as final determination if
1463 * client is NT or Win95. This is needed to return
1464 * the correct error codes in some circumstances.
1467 if(ra_type == RA_WINNT || ra_type == RA_WIN2K ||
1468 ra_type == RA_WIN95) {
1469 if(!(global_client_caps & (CAP_NT_SMBS|
1470 CAP_STATUS32))) {
1471 set_remote_arch( RA_WIN95);
1476 if (!doencrypt) {
1477 /* both Win95 and WinNT stuff up the password
1478 * lengths for non-encrypting systems. Uggh.
1480 if passlen1==24 its a win95 system, and its setting
1481 the password length incorrectly. Luckily it still
1482 works with the default code because Win95 will null
1483 terminate the password anyway
1485 if passlen1>0 and passlen2>0 then maybe its a NT box
1486 and its setting passlen2 to some random value which
1487 really stuffs things up. we need to fix that one. */
1489 if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 &&
1490 passlen2 != 1) {
1491 passlen2 = 0;
1495 /* check for nasty tricks */
1496 if (passlen1 > MAX_PASS_LEN
1497 || passlen1 > smbreq_bufrem(req, p)) {
1498 reply_nterror(req, nt_status_squash(
1499 NT_STATUS_INVALID_PARAMETER));
1500 END_PROFILE(SMBsesssetupX);
1501 return;
1504 if (passlen2 > MAX_PASS_LEN
1505 || passlen2 > smbreq_bufrem(req, p+passlen1)) {
1506 reply_nterror(req, nt_status_squash(
1507 NT_STATUS_INVALID_PARAMETER));
1508 END_PROFILE(SMBsesssetupX);
1509 return;
1512 /* Save the lanman2 password and the NT md4 password. */
1514 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
1515 doencrypt = False;
1518 if (doencrypt) {
1519 lm_resp = data_blob(p, passlen1);
1520 nt_resp = data_blob(p+passlen1, passlen2);
1521 } else if (lp_security() != SEC_SHARE) {
1523 * In share level we should ignore any passwords, so
1524 * only read them if we're not.
1526 char *pass = NULL;
1527 bool unic= smb_flag2 & FLAGS2_UNICODE_STRINGS;
1529 if (unic && (passlen2 == 0) && passlen1) {
1530 /* Only a ascii plaintext password was sent. */
1531 (void)srvstr_pull_talloc(talloc_tos(),
1532 req->inbuf,
1533 req->flags2,
1534 &pass,
1535 req->buf,
1536 passlen1,
1537 STR_TERMINATE|STR_ASCII);
1538 } else {
1539 (void)srvstr_pull_talloc(talloc_tos(),
1540 req->inbuf,
1541 req->flags2,
1542 &pass,
1543 req->buf,
1544 unic ? passlen2 : passlen1,
1545 STR_TERMINATE);
1547 if (!pass) {
1548 reply_nterror(req, nt_status_squash(
1549 NT_STATUS_INVALID_PARAMETER));
1550 END_PROFILE(SMBsesssetupX);
1551 return;
1553 plaintext_password = data_blob(pass, strlen(pass)+1);
1556 p += passlen1 + passlen2;
1558 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1559 STR_TERMINATE);
1560 user = tmp ? tmp : "";
1562 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1563 STR_TERMINATE);
1564 domain = tmp ? tmp : "";
1566 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1567 STR_TERMINATE);
1568 native_os = tmp ? tmp : "";
1570 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1571 STR_TERMINATE);
1572 native_lanman = tmp ? tmp : "";
1574 /* not documented or decoded by Ethereal but there is one more
1575 * string in the extra bytes which is the same as the
1576 * PrimaryDomain when using extended security. Windows NT 4
1577 * and 2003 use this string to store the native lanman string.
1578 * Windows 9x does not include a string here at all so we have
1579 * to check if we have any extra bytes left */
1581 byte_count = SVAL(req->vwv+13, 0);
1582 if ( PTR_DIFF(p, save_p) < byte_count) {
1583 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1584 STR_TERMINATE);
1585 primary_domain = tmp ? tmp : "";
1586 } else {
1587 primary_domain = talloc_strdup(talloc_tos(), "null");
1590 DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s] "
1591 "PrimaryDomain=[%s]\n",
1592 domain, native_os, native_lanman, primary_domain));
1594 if ( ra_type == RA_WIN2K ) {
1595 if ( strlen(native_lanman) == 0 )
1596 ra_lanman_string( primary_domain );
1597 else
1598 ra_lanman_string( native_lanman );
1603 if (SVAL(req->vwv+4, 0) == 0) {
1604 setup_new_vc_session();
1607 DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n",
1608 domain, user, get_remote_machine_name()));
1610 if (*user) {
1611 if (global_spnego_negotiated) {
1613 /* This has to be here, because this is a perfectly
1614 * valid behaviour for guest logons :-( */
1616 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt "
1617 "at 'normal' session setup after "
1618 "negotiating spnego.\n"));
1619 reply_nterror(req, nt_status_squash(
1620 NT_STATUS_LOGON_FAILURE));
1621 END_PROFILE(SMBsesssetupX);
1622 return;
1624 fstrcpy(sub_user, user);
1625 } else {
1626 fstrcpy(sub_user, lp_guestaccount());
1629 sub_set_smb_name(sub_user);
1631 reload_services(True);
1633 if (lp_security() == SEC_SHARE) {
1634 /* In share level we should ignore any passwords */
1636 data_blob_free(&lm_resp);
1637 data_blob_free(&nt_resp);
1638 data_blob_clear_free(&plaintext_password);
1640 map_username(sub_user);
1641 add_session_user(sub_user);
1642 add_session_workgroup(domain);
1643 /* Then force it to null for the benfit of the code below */
1644 user = "";
1647 if (!*user) {
1649 nt_status = check_guest_password(&server_info);
1651 } else if (doencrypt) {
1652 if (!negprot_global_auth_context) {
1653 DEBUG(0, ("reply_sesssetup_and_X: Attempted encrypted "
1654 "session setup without negprot denied!\n"));
1655 reply_nterror(req, nt_status_squash(
1656 NT_STATUS_LOGON_FAILURE));
1657 END_PROFILE(SMBsesssetupX);
1658 return;
1660 nt_status = make_user_info_for_reply_enc(&user_info, user,
1661 domain,
1662 lm_resp, nt_resp);
1663 if (NT_STATUS_IS_OK(nt_status)) {
1664 nt_status = negprot_global_auth_context->check_ntlm_password(
1665 negprot_global_auth_context,
1666 user_info,
1667 &server_info);
1669 } else {
1670 struct auth_context *plaintext_auth_context = NULL;
1672 nt_status = make_auth_context_subsystem(
1673 &plaintext_auth_context);
1675 if (NT_STATUS_IS_OK(nt_status)) {
1676 uint8_t chal[8];
1678 plaintext_auth_context->get_ntlm_challenge(
1679 plaintext_auth_context, chal);
1681 if (!make_user_info_for_reply(&user_info,
1682 user, domain, chal,
1683 plaintext_password)) {
1684 nt_status = NT_STATUS_NO_MEMORY;
1687 if (NT_STATUS_IS_OK(nt_status)) {
1688 nt_status = plaintext_auth_context->check_ntlm_password(
1689 plaintext_auth_context,
1690 user_info,
1691 &server_info);
1693 (plaintext_auth_context->free)(
1694 &plaintext_auth_context);
1699 free_user_info(&user_info);
1701 if (!NT_STATUS_IS_OK(nt_status)) {
1702 nt_status = do_map_to_guest(nt_status, &server_info,
1703 user, domain);
1706 if (!NT_STATUS_IS_OK(nt_status)) {
1707 data_blob_free(&nt_resp);
1708 data_blob_free(&lm_resp);
1709 data_blob_clear_free(&plaintext_password);
1710 reply_nterror(req, nt_status_squash(nt_status));
1711 END_PROFILE(SMBsesssetupX);
1712 return;
1715 /* Ensure we can't possible take a code path leading to a
1716 * null defref. */
1717 if (!server_info) {
1718 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1719 END_PROFILE(SMBsesssetupX);
1720 return;
1723 if (!server_info->ptok) {
1724 nt_status = create_local_token(server_info);
1726 if (!NT_STATUS_IS_OK(nt_status)) {
1727 DEBUG(10, ("create_local_token failed: %s\n",
1728 nt_errstr(nt_status)));
1729 data_blob_free(&nt_resp);
1730 data_blob_free(&lm_resp);
1731 data_blob_clear_free(&plaintext_password);
1732 reply_nterror(req, nt_status_squash(nt_status));
1733 END_PROFILE(SMBsesssetupX);
1734 return;
1738 data_blob_clear_free(&plaintext_password);
1740 /* it's ok - setup a reply */
1741 reply_outbuf(req, 3, 0);
1742 if (Protocol >= PROTOCOL_NT1) {
1743 push_signature(&req->outbuf);
1744 /* perhaps grab OS version here?? */
1747 if (server_info->guest) {
1748 SSVAL(req->outbuf,smb_vwv2,1);
1751 /* register the name and uid as being validated, so further connections
1752 to a uid can get through without a password, on the same VC */
1754 if (lp_security() == SEC_SHARE) {
1755 sess_vuid = UID_FIELD_INVALID;
1756 TALLOC_FREE(server_info);
1757 } else {
1758 /* Ignore the initial vuid. */
1759 sess_vuid = register_initial_vuid();
1760 if (sess_vuid == UID_FIELD_INVALID) {
1761 data_blob_free(&nt_resp);
1762 data_blob_free(&lm_resp);
1763 reply_nterror(req, nt_status_squash(
1764 NT_STATUS_LOGON_FAILURE));
1765 END_PROFILE(SMBsesssetupX);
1766 return;
1768 /* register_existing_vuid keeps the server info */
1769 sess_vuid = register_existing_vuid(sess_vuid,
1770 server_info,
1771 nt_resp.data ? nt_resp : lm_resp,
1772 sub_user);
1773 if (sess_vuid == UID_FIELD_INVALID) {
1774 data_blob_free(&nt_resp);
1775 data_blob_free(&lm_resp);
1776 reply_nterror(req, nt_status_squash(
1777 NT_STATUS_LOGON_FAILURE));
1778 END_PROFILE(SMBsesssetupX);
1779 return;
1782 /* current_user_info is changed on new vuid */
1783 reload_services( True );
1786 data_blob_free(&nt_resp);
1787 data_blob_free(&lm_resp);
1789 SSVAL(req->outbuf,smb_uid,sess_vuid);
1790 SSVAL(req->inbuf,smb_uid,sess_vuid);
1792 if (!done_sesssetup)
1793 max_send = MIN(max_send,smb_bufsize);
1795 done_sesssetup = True;
1797 END_PROFILE(SMBsesssetupX);
1798 chain_reply(req);
1799 return;