s3:net ads join: improve status evaluation for call to net_update_dns()
[Samba/bb.git] / source3 / smbd / sesssetup.c
blobca380a836e6f294e1dfd5a852c42b0d5b84345f8
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 "../lib/tsocket/tsocket.h"
27 #include "smbd/smbd.h"
28 #include "smbd/globals.h"
29 #include "../libcli/auth/spnego.h"
30 #include "../auth/ntlmssp/ntlmssp.h"
31 #include "../librpc/gen_ndr/krb5pac.h"
32 #include "libads/kerberos_proto.h"
33 #include "../lib/util/asn1.h"
34 #include "auth.h"
35 #include "messages.h"
36 #include "smbprofile.h"
37 #include "../libcli/security/security.h"
38 #include "auth/gensec/gensec.h"
40 /* For split krb5 SPNEGO blobs. */
41 struct pending_auth_data {
42 struct pending_auth_data *prev, *next;
43 uint16 vuid; /* Tag for this entry. */
44 uint16 smbpid; /* Alternate tag for this entry. */
45 size_t needed_len;
46 DATA_BLOB partial_data;
49 /****************************************************************************
50 Add the standard 'Samba' signature to the end of the session setup.
51 ****************************************************************************/
53 static int push_signature(uint8 **outbuf)
55 char *lanman;
56 int result, tmp;
58 result = 0;
60 tmp = message_push_string(outbuf, "Unix", STR_TERMINATE);
62 if (tmp == -1) return -1;
63 result += tmp;
65 if (asprintf(&lanman, "Samba %s", samba_version_string()) != -1) {
66 tmp = message_push_string(outbuf, lanman, STR_TERMINATE);
67 SAFE_FREE(lanman);
69 else {
70 tmp = message_push_string(outbuf, "Samba", STR_TERMINATE);
73 if (tmp == -1) return -1;
74 result += tmp;
76 tmp = message_push_string(outbuf, lp_workgroup(), STR_TERMINATE);
78 if (tmp == -1) return -1;
79 result += tmp;
81 return result;
84 /****************************************************************************
85 Send a security blob via a session setup reply.
86 ****************************************************************************/
88 static void reply_sesssetup_blob(struct smb_request *req,
89 DATA_BLOB blob,
90 NTSTATUS nt_status)
92 if (!NT_STATUS_IS_OK(nt_status) &&
93 !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
94 reply_nterror(req, nt_status_squash(nt_status));
95 return;
98 nt_status = nt_status_squash(nt_status);
99 SIVAL(req->outbuf, smb_rcls, NT_STATUS_V(nt_status));
100 SSVAL(req->outbuf, smb_vwv0, 0xFF); /* no chaining possible */
101 SSVAL(req->outbuf, smb_vwv3, blob.length);
103 if ((message_push_blob(&req->outbuf, blob) == -1)
104 || (push_signature(&req->outbuf) == -1)) {
105 reply_nterror(req, NT_STATUS_NO_MEMORY);
109 /****************************************************************************
110 Do a 'guest' logon, getting back the
111 ****************************************************************************/
113 static NTSTATUS check_guest_password(const struct tsocket_address *remote_address,
114 struct auth_serversupplied_info **server_info)
116 struct auth_context *auth_context;
117 struct auth_usersupplied_info *user_info = NULL;
119 NTSTATUS nt_status;
120 static unsigned char chal[8] = { 0, };
122 DEBUG(3,("Got anonymous request\n"));
124 nt_status = make_auth_context_fixed(talloc_tos(), &auth_context, chal);
125 if (!NT_STATUS_IS_OK(nt_status)) {
126 return nt_status;
129 if (!make_user_info_guest(remote_address, &user_info)) {
130 TALLOC_FREE(auth_context);
131 return NT_STATUS_NO_MEMORY;
134 nt_status = auth_context->check_ntlm_password(auth_context,
135 user_info,
136 server_info);
137 TALLOC_FREE(auth_context);
138 free_user_info(&user_info);
139 return nt_status;
143 #ifdef HAVE_KRB5
145 #if 0
146 /* Experiment that failed. See "only happens with a KDC" comment below. */
147 /****************************************************************************
148 Cerate a clock skew error blob for a Windows client.
149 ****************************************************************************/
151 static bool make_krb5_skew_error(DATA_BLOB *pblob_out)
153 krb5_context context = NULL;
154 krb5_error_code kerr = 0;
155 krb5_data reply;
156 krb5_principal host_princ = NULL;
157 char *host_princ_s = NULL;
158 bool ret = False;
160 *pblob_out = data_blob_null;
162 initialize_krb5_error_table();
163 kerr = krb5_init_context(&context);
164 if (kerr) {
165 return False;
167 /* Create server principal. */
168 asprintf(&host_princ_s, "%s$@%s", lp_netbios_name(), lp_realm());
169 if (!host_princ_s) {
170 goto out;
172 strlower_m(host_princ_s);
174 kerr = smb_krb5_parse_name(context, host_princ_s, &host_princ);
175 if (kerr) {
176 DEBUG(10,("make_krb5_skew_error: smb_krb5_parse_name failed "
177 "for name %s: Error %s\n",
178 host_princ_s, error_message(kerr) ));
179 goto out;
182 kerr = smb_krb5_mk_error(context, KRB5KRB_AP_ERR_SKEW,
183 host_princ, &reply);
184 if (kerr) {
185 DEBUG(10,("make_krb5_skew_error: smb_krb5_mk_error "
186 "failed: Error %s\n",
187 error_message(kerr) ));
188 goto out;
191 *pblob_out = data_blob(reply.data, reply.length);
192 kerberos_free_data_contents(context,&reply);
193 ret = True;
195 out:
197 if (host_princ_s) {
198 SAFE_FREE(host_princ_s);
200 if (host_princ) {
201 krb5_free_principal(context, host_princ);
203 krb5_free_context(context);
204 return ret;
206 #endif
208 /****************************************************************************
209 Reply to a session setup spnego negotiate packet for kerberos.
210 ****************************************************************************/
212 static void reply_spnego_kerberos(struct smb_request *req,
213 DATA_BLOB *secblob,
214 const char *mechOID,
215 uint16 vuid,
216 bool *p_invalidate_vuid)
218 TALLOC_CTX *mem_ctx;
219 DATA_BLOB ticket;
220 struct passwd *pw;
221 int sess_vuid = req->vuid;
222 NTSTATUS ret = NT_STATUS_OK;
223 DATA_BLOB ap_rep, ap_rep_wrapped, response;
224 struct auth_session_info *session_info = NULL;
225 DATA_BLOB session_key = data_blob_null;
226 uint8 tok_id[2];
227 DATA_BLOB nullblob = data_blob_null;
228 bool map_domainuser_to_guest = False;
229 bool username_was_mapped;
230 struct PAC_LOGON_INFO *logon_info = NULL;
231 struct smbd_server_connection *sconn = req->sconn;
232 char *principal;
233 char *user;
234 char *domain;
235 char *real_username;
237 ZERO_STRUCT(ticket);
238 ZERO_STRUCT(ap_rep);
239 ZERO_STRUCT(ap_rep_wrapped);
240 ZERO_STRUCT(response);
242 /* Normally we will always invalidate the intermediate vuid. */
243 *p_invalidate_vuid = True;
245 mem_ctx = talloc_init("reply_spnego_kerberos");
246 if (mem_ctx == NULL) {
247 reply_nterror(req, nt_status_squash(NT_STATUS_NO_MEMORY));
248 return;
251 if (!spnego_parse_krb5_wrap(mem_ctx, *secblob, &ticket, tok_id)) {
252 talloc_destroy(mem_ctx);
253 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
254 return;
257 ret = ads_verify_ticket(mem_ctx, lp_realm(), 0, &ticket,
258 &principal, &logon_info, &ap_rep,
259 &session_key, True);
261 data_blob_free(&ticket);
263 if (!NT_STATUS_IS_OK(ret)) {
264 #if 0
265 /* Experiment that failed.
266 * See "only happens with a KDC" comment below. */
268 if (NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
271 * Windows in this case returns
272 * NT_STATUS_MORE_PROCESSING_REQUIRED
273 * with a negTokenTarg blob containing an krb5_error
274 * struct ASN1 encoded containing KRB5KRB_AP_ERR_SKEW.
275 * The client then fixes its clock and continues rather
276 * than giving an error. JRA.
277 * -- Looks like this only happens with a KDC. JRA.
280 bool ok = make_krb5_skew_error(&ap_rep);
281 if (!ok) {
282 talloc_destroy(mem_ctx);
283 return ERROR_NT(nt_status_squash(
284 NT_STATUS_LOGON_FAILURE));
286 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep,
287 TOK_ID_KRB_ERROR);
288 response = spnego_gen_auth_response(&ap_rep_wrapped,
289 ret, OID_KERBEROS5_OLD);
290 reply_sesssetup_blob(conn, inbuf, outbuf, response,
291 NT_STATUS_MORE_PROCESSING_REQUIRED);
294 * In this one case we don't invalidate the
295 * intermediate vuid as we're expecting the client
296 * to re-use it for the next sessionsetupX packet. JRA.
299 *p_invalidate_vuid = False;
301 data_blob_free(&ap_rep);
302 data_blob_free(&ap_rep_wrapped);
303 data_blob_free(&response);
304 talloc_destroy(mem_ctx);
305 return -1; /* already replied */
307 #else
308 if (!NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
309 ret = NT_STATUS_LOGON_FAILURE;
311 #endif
312 DEBUG(1,("Failed to verify incoming ticket with error %s!\n",
313 nt_errstr(ret)));
314 talloc_destroy(mem_ctx);
315 reply_nterror(req, nt_status_squash(ret));
316 return;
319 ret = get_user_from_kerberos_info(talloc_tos(),
320 sconn->remote_hostname,
321 principal, logon_info,
322 &username_was_mapped,
323 &map_domainuser_to_guest,
324 &user, &domain,
325 &real_username, &pw);
326 if (!NT_STATUS_IS_OK(ret)) {
327 data_blob_free(&ap_rep);
328 data_blob_free(&session_key);
329 talloc_destroy(mem_ctx);
330 reply_nterror(req,nt_status_squash(NT_STATUS_LOGON_FAILURE));
331 return;
334 /* save the PAC data if we have it */
335 if (logon_info) {
336 netsamlogon_cache_store(user, &logon_info->info3);
339 /* setup the string used by %U */
340 sub_set_smb_name(real_username);
342 /* reload services so that the new %U is taken into account */
343 reload_services(sconn, conn_snum_used, true);
345 ret = make_session_info_krb5(mem_ctx,
346 user, domain, real_username, pw,
347 logon_info, map_domainuser_to_guest,
348 username_was_mapped,
349 &session_key,
350 &session_info);
351 data_blob_free(&session_key);
352 if (!NT_STATUS_IS_OK(ret)) {
353 DEBUG(1, ("make_server_info_krb5 failed!\n"));
354 data_blob_free(&ap_rep);
355 TALLOC_FREE(mem_ctx);
356 reply_nterror(req, nt_status_squash(ret));
357 return;
360 if (!is_partial_auth_vuid(sconn, sess_vuid)) {
361 sess_vuid = register_initial_vuid(sconn);
364 /* register_existing_vuid keeps the server info */
365 /* register_existing_vuid takes ownership of session_key on success,
366 * no need to free after this on success. A better interface would copy
367 * it.... */
369 sess_vuid = register_existing_vuid(sconn, sess_vuid,
370 session_info, nullblob);
372 reply_outbuf(req, 4, 0);
373 SSVAL(req->outbuf,smb_uid,sess_vuid);
375 if (sess_vuid == UID_FIELD_INVALID ) {
376 ret = NT_STATUS_LOGON_FAILURE;
377 } else {
378 /* current_user_info is changed on new vuid */
379 reload_services(sconn, conn_snum_used, true);
381 SSVAL(req->outbuf, smb_vwv3, 0);
383 if (security_session_user_level(session_info, NULL) < SECURITY_USER) {
384 SSVAL(req->outbuf,smb_vwv2,1);
387 SSVAL(req->outbuf, smb_uid, sess_vuid);
389 /* Successful logon. Keep this vuid. */
390 *p_invalidate_vuid = False;
393 /* wrap that up in a nice GSS-API wrapping */
394 if (NT_STATUS_IS_OK(ret)) {
395 ap_rep_wrapped = spnego_gen_krb5_wrap(talloc_tos(), ap_rep,
396 TOK_ID_KRB_AP_REP);
397 } else {
398 ap_rep_wrapped = data_blob_null;
400 response = spnego_gen_auth_response(talloc_tos(), &ap_rep_wrapped, ret,
401 mechOID);
402 reply_sesssetup_blob(req, response, ret);
404 data_blob_free(&ap_rep);
405 data_blob_free(&ap_rep_wrapped);
406 data_blob_free(&response);
407 TALLOC_FREE(mem_ctx);
410 #endif
412 /****************************************************************************
413 Send a session setup reply, wrapped in SPNEGO.
414 Get vuid and check first.
415 End the NTLMSSP exchange context if we are OK/complete fail
416 This should be split into two functions, one to handle each
417 leg of the NTLM auth steps.
418 ***************************************************************************/
420 static void reply_spnego_ntlmssp(struct smb_request *req,
421 uint16 vuid,
422 struct gensec_security **gensec_security,
423 DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status,
424 const char *OID,
425 bool wrap)
427 bool do_invalidate = true;
428 DATA_BLOB response;
429 struct auth_session_info *session_info = NULL;
430 struct smbd_server_connection *sconn = req->sconn;
432 if (NT_STATUS_IS_OK(nt_status)) {
433 nt_status = gensec_session_info(*gensec_security,
434 talloc_tos(),
435 &session_info);
438 reply_outbuf(req, 4, 0);
440 SSVAL(req->outbuf, smb_uid, vuid);
442 if (NT_STATUS_IS_OK(nt_status)) {
443 DATA_BLOB nullblob = data_blob_null;
445 if (!is_partial_auth_vuid(sconn, vuid)) {
446 nt_status = NT_STATUS_LOGON_FAILURE;
447 goto out;
450 /* register_existing_vuid keeps the server info */
451 if (register_existing_vuid(sconn, vuid,
452 session_info, nullblob) !=
453 vuid) {
454 /* The problem is, *gensec_security points
455 * into the vuser this will have
456 * talloc_free()'ed in
457 * register_existing_vuid() */
458 do_invalidate = false;
459 nt_status = NT_STATUS_LOGON_FAILURE;
460 goto out;
463 /* current_user_info is changed on new vuid */
464 reload_services(sconn, conn_snum_used, true);
466 SSVAL(req->outbuf, smb_vwv3, 0);
468 if (security_session_user_level(session_info, NULL) < SECURITY_USER) {
469 SSVAL(req->outbuf,smb_vwv2,1);
473 out:
475 if (wrap) {
476 response = spnego_gen_auth_response(talloc_tos(),
477 ntlmssp_blob,
478 nt_status, OID);
479 } else {
480 response = *ntlmssp_blob;
483 reply_sesssetup_blob(req, response, nt_status);
484 if (wrap) {
485 data_blob_free(&response);
488 /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
489 and the other end, that we are not finished yet. */
491 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
492 /* NB. This is *NOT* an error case. JRA */
493 if (do_invalidate) {
494 TALLOC_FREE(*gensec_security);
495 if (!NT_STATUS_IS_OK(nt_status)) {
496 /* Kill the intermediate vuid */
497 invalidate_vuid(sconn, vuid);
503 /****************************************************************************
504 Is this a krb5 mechanism ?
505 ****************************************************************************/
507 NTSTATUS parse_spnego_mechanisms(TALLOC_CTX *ctx,
508 DATA_BLOB blob_in,
509 DATA_BLOB *pblob_out,
510 char **kerb_mechOID)
512 char *OIDs[ASN1_MAX_OIDS];
513 int i;
514 NTSTATUS ret = NT_STATUS_OK;
516 *kerb_mechOID = NULL;
518 /* parse out the OIDs and the first sec blob */
519 if (!spnego_parse_negTokenInit(ctx, blob_in, OIDs, NULL, pblob_out) ||
520 (OIDs[0] == NULL)) {
521 return NT_STATUS_LOGON_FAILURE;
524 /* only look at the first OID for determining the mechToken --
525 according to RFC2478, we should choose the one we want
526 and renegotiate, but i smell a client bug here..
528 Problem observed when connecting to a member (samba box)
529 of an AD domain as a user in a Samba domain. Samba member
530 server sent back krb5/mskrb5/ntlmssp as mechtypes, but the
531 client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an
532 NTLMSSP mechtoken. --jerry */
534 #ifdef HAVE_KRB5
535 if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||
536 strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
537 *kerb_mechOID = talloc_strdup(ctx, OIDs[0]);
538 if (*kerb_mechOID == NULL) {
539 ret = NT_STATUS_NO_MEMORY;
542 #endif
544 for (i=0;OIDs[i];i++) {
545 DEBUG(5,("parse_spnego_mechanisms: Got OID %s\n", OIDs[i]));
546 talloc_free(OIDs[i]);
548 return ret;
551 /****************************************************************************
552 Fall back from krb5 to NTLMSSP.
553 ****************************************************************************/
555 static void reply_spnego_downgrade_to_ntlmssp(struct smb_request *req,
556 uint16 vuid)
558 DATA_BLOB response;
560 reply_outbuf(req, 4, 0);
561 SSVAL(req->outbuf,smb_uid,vuid);
563 DEBUG(3,("reply_spnego_downgrade_to_ntlmssp: Got krb5 ticket in SPNEGO "
564 "but set to downgrade to NTLMSSP\n"));
566 response = spnego_gen_auth_response(talloc_tos(), NULL,
567 NT_STATUS_MORE_PROCESSING_REQUIRED,
568 OID_NTLMSSP);
569 reply_sesssetup_blob(req, response, NT_STATUS_MORE_PROCESSING_REQUIRED);
570 data_blob_free(&response);
573 /****************************************************************************
574 Reply to a session setup spnego negotiate packet.
575 ****************************************************************************/
577 static void reply_spnego_negotiate(struct smb_request *req,
578 uint16 vuid,
579 DATA_BLOB blob1,
580 struct gensec_security **gensec_security)
582 DATA_BLOB secblob;
583 DATA_BLOB chal;
584 char *kerb_mech = NULL;
585 NTSTATUS status;
586 struct smbd_server_connection *sconn = req->sconn;
588 status = parse_spnego_mechanisms(talloc_tos(),
589 blob1, &secblob, &kerb_mech);
590 if (!NT_STATUS_IS_OK(status)) {
591 /* Kill the intermediate vuid */
592 invalidate_vuid(sconn, vuid);
593 reply_nterror(req, nt_status_squash(status));
594 return;
597 DEBUG(3,("reply_spnego_negotiate: Got secblob of size %lu\n",
598 (unsigned long)secblob.length));
600 #ifdef HAVE_KRB5
601 if (kerb_mech && ((lp_security()==SEC_ADS) ||
602 USE_KERBEROS_KEYTAB) ) {
603 bool destroy_vuid = True;
604 reply_spnego_kerberos(req, &secblob, kerb_mech,
605 vuid, &destroy_vuid);
606 data_blob_free(&secblob);
607 if (destroy_vuid) {
608 /* Kill the intermediate vuid */
609 invalidate_vuid(sconn, vuid);
611 TALLOC_FREE(kerb_mech);
612 return;
614 #endif
616 TALLOC_FREE(*gensec_security);
618 if (kerb_mech) {
619 data_blob_free(&secblob);
620 /* The mechtoken is a krb5 ticket, but
621 * we need to fall back to NTLM. */
622 reply_spnego_downgrade_to_ntlmssp(req, vuid);
623 TALLOC_FREE(kerb_mech);
624 return;
627 status = auth_generic_prepare(NULL, sconn->remote_address,
628 gensec_security);
629 if (!NT_STATUS_IS_OK(status)) {
630 /* Kill the intermediate vuid */
631 invalidate_vuid(sconn, vuid);
632 reply_nterror(req, nt_status_squash(status));
633 return;
636 gensec_want_feature(*gensec_security, GENSEC_FEATURE_SESSION_KEY);
637 gensec_want_feature(*gensec_security, GENSEC_FEATURE_UNIX_TOKEN);
639 status = gensec_start_mech_by_oid(*gensec_security, GENSEC_OID_NTLMSSP);
640 if (!NT_STATUS_IS_OK(status)) {
641 /* Kill the intermediate vuid */
642 invalidate_vuid(sconn, vuid);
643 reply_nterror(req, nt_status_squash(status));
644 return;
647 status = gensec_update(*gensec_security, talloc_tos(),
648 NULL, secblob, &chal);
650 data_blob_free(&secblob);
652 reply_spnego_ntlmssp(req, vuid, gensec_security,
653 &chal, status, OID_NTLMSSP, true);
655 data_blob_free(&chal);
657 /* already replied */
658 return;
661 /****************************************************************************
662 Reply to a session setup spnego auth packet.
663 ****************************************************************************/
665 static void reply_spnego_auth(struct smb_request *req,
666 uint16 vuid,
667 DATA_BLOB blob1,
668 struct gensec_security **gensec_security)
670 DATA_BLOB auth = data_blob_null;
671 DATA_BLOB auth_reply = data_blob_null;
672 DATA_BLOB secblob = data_blob_null;
673 NTSTATUS status = NT_STATUS_LOGON_FAILURE;
674 struct smbd_server_connection *sconn = req->sconn;
676 if (!spnego_parse_auth(talloc_tos(), blob1, &auth)) {
677 #if 0
678 file_save("auth.dat", blob1.data, blob1.length);
679 #endif
680 /* Kill the intermediate vuid */
681 invalidate_vuid(sconn, vuid);
683 reply_nterror(req, nt_status_squash(
684 NT_STATUS_LOGON_FAILURE));
685 return;
688 if (auth.data[0] == ASN1_APPLICATION(0)) {
689 /* Might be a second negTokenTarg packet */
690 char *kerb_mech = NULL;
692 status = parse_spnego_mechanisms(talloc_tos(),
693 auth, &secblob, &kerb_mech);
695 if (!NT_STATUS_IS_OK(status)) {
696 /* Kill the intermediate vuid */
697 invalidate_vuid(sconn, vuid);
698 reply_nterror(req, nt_status_squash(status));
699 return;
702 DEBUG(3,("reply_spnego_auth: Got secblob of size %lu\n",
703 (unsigned long)secblob.length));
704 #ifdef HAVE_KRB5
705 if (kerb_mech && ((lp_security()==SEC_ADS) ||
706 USE_KERBEROS_KEYTAB)) {
707 bool destroy_vuid = True;
708 reply_spnego_kerberos(req, &secblob, kerb_mech,
709 vuid, &destroy_vuid);
710 data_blob_free(&secblob);
711 data_blob_free(&auth);
712 if (destroy_vuid) {
713 /* Kill the intermediate vuid */
714 invalidate_vuid(sconn, vuid);
716 TALLOC_FREE(kerb_mech);
717 return;
719 #endif
720 /* Can't blunder into NTLMSSP auth if we have
721 * a krb5 ticket. */
723 if (kerb_mech) {
724 /* Kill the intermediate vuid */
725 invalidate_vuid(sconn, vuid);
726 DEBUG(3,("reply_spnego_auth: network "
727 "misconfiguration, client sent us a "
728 "krb5 ticket and kerberos security "
729 "not enabled\n"));
730 reply_nterror(req, nt_status_squash(
731 NT_STATUS_LOGON_FAILURE));
732 TALLOC_FREE(kerb_mech);
736 /* If we get here it wasn't a negTokenTarg auth packet. */
737 data_blob_free(&secblob);
739 if (!*gensec_security) {
740 status = auth_generic_prepare(NULL, sconn->remote_address,
741 gensec_security);
742 if (!NT_STATUS_IS_OK(status)) {
743 /* Kill the intermediate vuid */
744 invalidate_vuid(sconn, vuid);
745 reply_nterror(req, nt_status_squash(status));
746 return;
749 gensec_want_feature(*gensec_security, GENSEC_FEATURE_SESSION_KEY);
750 gensec_want_feature(*gensec_security, GENSEC_FEATURE_UNIX_TOKEN);
752 status = gensec_start_mech_by_oid(*gensec_security, GENSEC_OID_NTLMSSP);
753 if (!NT_STATUS_IS_OK(status)) {
754 /* Kill the intermediate vuid */
755 invalidate_vuid(sconn, vuid);
756 reply_nterror(req, nt_status_squash(status));
757 return;
761 status = gensec_update(*gensec_security, talloc_tos(),
762 NULL, auth, &auth_reply);
764 data_blob_free(&auth);
766 /* Don't send the mechid as we've already sent this (RFC4178). */
768 reply_spnego_ntlmssp(req, vuid,
769 gensec_security,
770 &auth_reply, status, NULL, true);
772 data_blob_free(&auth_reply);
774 /* and tell smbd that we have already replied to this packet */
775 return;
778 /****************************************************************************
779 Delete an entry on the list.
780 ****************************************************************************/
782 static void delete_partial_auth(struct smbd_server_connection *sconn,
783 struct pending_auth_data *pad)
785 if (!pad) {
786 return;
788 DLIST_REMOVE(sconn->smb1.pd_list, pad);
789 data_blob_free(&pad->partial_data);
790 SAFE_FREE(pad);
793 /****************************************************************************
794 Search for a partial SPNEGO auth fragment matching an smbpid.
795 ****************************************************************************/
797 static struct pending_auth_data *get_pending_auth_data(
798 struct smbd_server_connection *sconn,
799 uint16_t smbpid)
801 struct pending_auth_data *pad;
803 * NOTE: using the smbpid here is completely wrong...
804 * see [MS-SMB]
805 * 3.3.5.3 Receiving an SMB_COM_SESSION_SETUP_ANDX Request
807 for (pad = sconn->smb1.pd_list; pad; pad = pad->next) {
808 if (pad->smbpid == smbpid) {
809 break;
812 return pad;
815 /****************************************************************************
816 Check the size of an SPNEGO blob. If we need more return
817 NT_STATUS_MORE_PROCESSING_REQUIRED, else return NT_STATUS_OK. Don't allow
818 the blob to be more than 64k.
819 ****************************************************************************/
821 static NTSTATUS check_spnego_blob_complete(struct smbd_server_connection *sconn,
822 uint16 smbpid, uint16 vuid,
823 DATA_BLOB *pblob)
825 struct pending_auth_data *pad = NULL;
826 ASN1_DATA *data;
827 size_t needed_len = 0;
829 pad = get_pending_auth_data(sconn, smbpid);
831 /* Ensure we have some data. */
832 if (pblob->length == 0) {
833 /* Caller can cope. */
834 DEBUG(2,("check_spnego_blob_complete: zero blob length !\n"));
835 delete_partial_auth(sconn, pad);
836 return NT_STATUS_OK;
839 /* Were we waiting for more data ? */
840 if (pad) {
841 DATA_BLOB tmp_blob;
842 size_t copy_len = MIN(65536, pblob->length);
844 /* Integer wrap paranoia.... */
846 if (pad->partial_data.length + copy_len <
847 pad->partial_data.length ||
848 pad->partial_data.length + copy_len < copy_len) {
850 DEBUG(2,("check_spnego_blob_complete: integer wrap "
851 "pad->partial_data.length = %u, "
852 "copy_len = %u\n",
853 (unsigned int)pad->partial_data.length,
854 (unsigned int)copy_len ));
856 delete_partial_auth(sconn, pad);
857 return NT_STATUS_INVALID_PARAMETER;
860 DEBUG(10,("check_spnego_blob_complete: "
861 "pad->partial_data.length = %u, "
862 "pad->needed_len = %u, "
863 "copy_len = %u, "
864 "pblob->length = %u,\n",
865 (unsigned int)pad->partial_data.length,
866 (unsigned int)pad->needed_len,
867 (unsigned int)copy_len,
868 (unsigned int)pblob->length ));
870 tmp_blob = data_blob(NULL,
871 pad->partial_data.length + copy_len);
873 /* Concatenate the two (up to copy_len) bytes. */
874 memcpy(tmp_blob.data,
875 pad->partial_data.data,
876 pad->partial_data.length);
877 memcpy(tmp_blob.data + pad->partial_data.length,
878 pblob->data,
879 copy_len);
881 /* Replace the partial data. */
882 data_blob_free(&pad->partial_data);
883 pad->partial_data = tmp_blob;
884 ZERO_STRUCT(tmp_blob);
886 /* Are we done ? */
887 if (pblob->length >= pad->needed_len) {
888 /* Yes, replace pblob. */
889 data_blob_free(pblob);
890 *pblob = pad->partial_data;
891 ZERO_STRUCT(pad->partial_data);
892 delete_partial_auth(sconn, pad);
893 return NT_STATUS_OK;
896 /* Still need more data. */
897 pad->needed_len -= copy_len;
898 return NT_STATUS_MORE_PROCESSING_REQUIRED;
901 if ((pblob->data[0] != ASN1_APPLICATION(0)) &&
902 (pblob->data[0] != ASN1_CONTEXT(1))) {
903 /* Not something we can determine the
904 * length of.
906 return NT_STATUS_OK;
909 /* This is a new SPNEGO sessionsetup - see if
910 * the data given in this blob is enough.
913 data = asn1_init(NULL);
914 if (data == NULL) {
915 return NT_STATUS_NO_MEMORY;
918 asn1_load(data, *pblob);
919 if (asn1_start_tag(data, pblob->data[0])) {
920 /* asn1_start_tag checks if the given
921 length of the blob is enough to complete
922 the tag. If it returns true we know
923 there is nothing to do - the blob is
924 complete. */
925 asn1_free(data);
926 return NT_STATUS_OK;
929 if (data->nesting == NULL) {
930 /* Incorrect tag, allocation failed,
931 or reading the tag length failed.
932 Let the caller catch. */
933 asn1_free(data);
934 return NT_STATUS_OK;
937 /* Here we know asn1_start_tag() has set data->has_error to true.
938 asn1_tag_remaining() will have failed due to the given blob
939 being too short. We need to work out how short. */
941 /* Integer wrap paranoia.... */
943 if (data->nesting->taglen + data->nesting->start < data->nesting->taglen ||
944 data->nesting->taglen + data->nesting->start < data->nesting->start) {
946 DEBUG(2,("check_spnego_blob_complete: integer wrap "
947 "data.nesting->taglen = %u, "
948 "data.nesting->start = %u\n",
949 (unsigned int)data->nesting->taglen,
950 (unsigned int)data->nesting->start ));
952 asn1_free(data);
953 return NT_STATUS_INVALID_PARAMETER;
956 /* Total length of the needed asn1 is the tag length
957 * plus the current offset. */
959 needed_len = data->nesting->taglen + data->nesting->start;
960 asn1_free(data);
962 DEBUG(10,("check_spnego_blob_complete: needed_len = %u, "
963 "pblob->length = %u\n",
964 (unsigned int)needed_len,
965 (unsigned int)pblob->length ));
967 if (needed_len <= pblob->length) {
968 /* Nothing to do - blob is complete. */
969 /* THIS SHOULD NOT HAPPEN - asn1_start_tag()
970 above should have caught this !!! */
971 DEBUG(0,("check_spnego_blob_complete: logic "
972 "error (needed_len = %u, "
973 "pblob->length = %u).\n",
974 (unsigned int)needed_len,
975 (unsigned int)pblob->length ));
976 return NT_STATUS_OK;
979 /* Refuse the blob if it's bigger than 64k. */
980 if (needed_len > 65536) {
981 DEBUG(2,("check_spnego_blob_complete: needed_len "
982 "too large (%u)\n",
983 (unsigned int)needed_len ));
984 return NT_STATUS_INVALID_PARAMETER;
987 /* We must store this blob until complete. */
988 if (!(pad = SMB_MALLOC_P(struct pending_auth_data))) {
989 return NT_STATUS_NO_MEMORY;
991 pad->needed_len = needed_len - pblob->length;
992 pad->partial_data = data_blob(pblob->data, pblob->length);
993 if (pad->partial_data.data == NULL) {
994 SAFE_FREE(pad);
995 return NT_STATUS_NO_MEMORY;
997 pad->smbpid = smbpid;
998 pad->vuid = vuid;
999 DLIST_ADD(sconn->smb1.pd_list, pad);
1001 return NT_STATUS_MORE_PROCESSING_REQUIRED;
1004 /****************************************************************************
1005 Reply to a session setup command.
1006 conn POINTER CAN BE NULL HERE !
1007 ****************************************************************************/
1009 static void reply_sesssetup_and_X_spnego(struct smb_request *req)
1011 const uint8 *p;
1012 DATA_BLOB blob1;
1013 size_t bufrem;
1014 char *tmp;
1015 const char *native_os;
1016 const char *native_lanman;
1017 const char *primary_domain;
1018 const char *p2;
1019 uint16 data_blob_len = SVAL(req->vwv+7, 0);
1020 enum remote_arch_types ra_type = get_remote_arch();
1021 int vuid = req->vuid;
1022 user_struct *vuser = NULL;
1023 NTSTATUS status = NT_STATUS_OK;
1024 uint16 smbpid = req->smbpid;
1025 struct smbd_server_connection *sconn = req->sconn;
1027 DEBUG(3,("Doing spnego session setup\n"));
1029 if (global_client_caps == 0) {
1030 global_client_caps = IVAL(req->vwv+10, 0);
1032 if (!(global_client_caps & CAP_STATUS32)) {
1033 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1038 p = req->buf;
1040 if (data_blob_len == 0) {
1041 /* an invalid request */
1042 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1043 return;
1046 bufrem = smbreq_bufrem(req, p);
1047 /* pull the spnego blob */
1048 blob1 = data_blob(p, MIN(bufrem, data_blob_len));
1050 #if 0
1051 file_save("negotiate.dat", blob1.data, blob1.length);
1052 #endif
1054 p2 = (const char *)req->buf + blob1.length;
1056 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1057 STR_TERMINATE);
1058 native_os = tmp ? tmp : "";
1060 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1061 STR_TERMINATE);
1062 native_lanman = tmp ? tmp : "";
1064 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1065 STR_TERMINATE);
1066 primary_domain = tmp ? tmp : "";
1068 DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
1069 native_os, native_lanman, primary_domain));
1071 if ( ra_type == RA_WIN2K ) {
1072 /* Vista sets neither the OS or lanman strings */
1074 if ( !strlen(native_os) && !strlen(native_lanman) )
1075 set_remote_arch(RA_VISTA);
1077 /* Windows 2003 doesn't set the native lanman string,
1078 but does set primary domain which is a bug I think */
1080 if ( !strlen(native_lanman) ) {
1081 ra_lanman_string( primary_domain );
1082 } else {
1083 ra_lanman_string( native_lanman );
1085 } else if ( ra_type == RA_VISTA ) {
1086 if ( strncmp(native_os, "Mac OS X", 8) == 0 ) {
1087 set_remote_arch(RA_OSX);
1091 /* Did we get a valid vuid ? */
1092 if (!is_partial_auth_vuid(sconn, vuid)) {
1093 /* No, then try and see if this is an intermediate sessionsetup
1094 * for a large SPNEGO packet. */
1095 struct pending_auth_data *pad;
1096 pad = get_pending_auth_data(sconn, smbpid);
1097 if (pad) {
1098 DEBUG(10,("reply_sesssetup_and_X_spnego: found "
1099 "pending vuid %u\n",
1100 (unsigned int)pad->vuid ));
1101 vuid = pad->vuid;
1105 /* Do we have a valid vuid now ? */
1106 if (!is_partial_auth_vuid(sconn, vuid)) {
1107 /* No, start a new authentication setup. */
1108 vuid = register_initial_vuid(sconn);
1109 if (vuid == UID_FIELD_INVALID) {
1110 data_blob_free(&blob1);
1111 reply_nterror(req, nt_status_squash(
1112 NT_STATUS_INVALID_PARAMETER));
1113 return;
1117 vuser = get_partial_auth_user_struct(sconn, vuid);
1118 /* This MUST be valid. */
1119 if (!vuser) {
1120 smb_panic("reply_sesssetup_and_X_spnego: invalid vuid.");
1123 /* Large (greater than 4k) SPNEGO blobs are split into multiple
1124 * sessionsetup requests as the Windows limit on the security blob
1125 * field is 4k. Bug #4400. JRA.
1128 status = check_spnego_blob_complete(sconn, smbpid, vuid, &blob1);
1129 if (!NT_STATUS_IS_OK(status)) {
1130 if (!NT_STATUS_EQUAL(status,
1131 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1132 /* Real error - kill the intermediate vuid */
1133 invalidate_vuid(sconn, vuid);
1135 data_blob_free(&blob1);
1136 reply_nterror(req, nt_status_squash(status));
1137 return;
1140 /* Handle either raw NTLMSSP or hand off the whole blob to
1141 * GENSEC. The processing at this layer is essentially
1142 * identical regardless. In particular, both rely only on the
1143 * status code (not the contents of the packet) and do not
1144 * wrap the result */
1145 if (sconn->use_gensec_hook || ntlmssp_blob_matches_magic(&blob1)) {
1146 DATA_BLOB chal;
1148 if (!vuser->gensec_security) {
1149 status = auth_generic_prepare(vuser, sconn->remote_address,
1150 &vuser->gensec_security);
1151 if (!NT_STATUS_IS_OK(status)) {
1152 /* Kill the intermediate vuid */
1153 invalidate_vuid(sconn, vuid);
1154 data_blob_free(&blob1);
1155 reply_nterror(req, nt_status_squash(status));
1156 return;
1159 gensec_want_feature(vuser->gensec_security, GENSEC_FEATURE_SESSION_KEY);
1160 gensec_want_feature(vuser->gensec_security, GENSEC_FEATURE_UNIX_TOKEN);
1162 if (sconn->use_gensec_hook) {
1163 status = gensec_start_mech_by_oid(vuser->gensec_security, GENSEC_OID_SPNEGO);
1164 } else {
1165 status = gensec_start_mech_by_oid(vuser->gensec_security, GENSEC_OID_NTLMSSP);
1167 if (!NT_STATUS_IS_OK(status)) {
1168 /* Kill the intermediate vuid */
1169 invalidate_vuid(sconn, vuid);
1170 data_blob_free(&blob1);
1171 reply_nterror(req, nt_status_squash(status));
1172 return;
1176 status = gensec_update(vuser->gensec_security,
1177 talloc_tos(), NULL,
1178 blob1, &chal);
1180 data_blob_free(&blob1);
1182 reply_spnego_ntlmssp(req, vuid,
1183 &vuser->gensec_security,
1184 &chal, status, NULL, false);
1185 data_blob_free(&chal);
1186 return;
1189 if (blob1.data[0] == ASN1_APPLICATION(0)) {
1191 /* its a negTokenTarg packet */
1193 reply_spnego_negotiate(req, vuid, blob1,
1194 &vuser->gensec_security);
1195 data_blob_free(&blob1);
1196 return;
1199 if (blob1.data[0] == ASN1_CONTEXT(1)) {
1201 /* its a auth packet */
1203 reply_spnego_auth(req, vuid, blob1,
1204 &vuser->gensec_security);
1205 data_blob_free(&blob1);
1206 return;
1209 /* what sort of packet is this? */
1210 DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
1212 data_blob_free(&blob1);
1214 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1217 /****************************************************************************
1218 On new VC == 0, shutdown *all* old connections and users.
1219 It seems that only NT4.x does this. At W2K and above (XP etc.).
1220 a new session setup with VC==0 is ignored.
1221 ****************************************************************************/
1223 struct shutdown_state {
1224 const char *ip;
1225 struct messaging_context *msg_ctx;
1228 static int shutdown_other_smbds(const struct connections_key *key,
1229 const struct connections_data *crec,
1230 void *private_data)
1232 struct shutdown_state *state = (struct shutdown_state *)private_data;
1234 DEBUG(10, ("shutdown_other_smbds: %s, %s\n",
1235 server_id_str(talloc_tos(), &crec->pid), crec->addr));
1237 if (!process_exists(crec->pid)) {
1238 DEBUG(10, ("process does not exist\n"));
1239 return 0;
1242 if (procid_is_me(&crec->pid)) {
1243 DEBUG(10, ("It's me\n"));
1244 return 0;
1247 if (strcmp(state->ip, crec->addr) != 0) {
1248 DEBUG(10, ("%s does not match %s\n", state->ip, crec->addr));
1249 return 0;
1252 DEBUG(1, ("shutdown_other_smbds: shutting down pid %u "
1253 "(IP %s)\n", (unsigned int)procid_to_pid(&crec->pid),
1254 state->ip));
1256 messaging_send(state->msg_ctx, crec->pid, MSG_SHUTDOWN,
1257 &data_blob_null);
1258 return 0;
1261 static void setup_new_vc_session(struct smbd_server_connection *sconn)
1263 DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x "
1264 "compatible we would close all old resources.\n"));
1265 #if 0
1266 conn_close_all();
1267 invalidate_all_vuids();
1268 #endif
1269 if (lp_reset_on_zero_vc()) {
1270 char *addr;
1271 struct shutdown_state state;
1273 addr = tsocket_address_inet_addr_string(
1274 sconn->remote_address, talloc_tos());
1275 if (addr == NULL) {
1276 return;
1278 state.ip = addr;
1279 state.msg_ctx = sconn->msg_ctx;
1280 connections_forall_read(shutdown_other_smbds, &state);
1281 TALLOC_FREE(addr);
1285 /****************************************************************************
1286 Reply to a session setup command.
1287 ****************************************************************************/
1289 void reply_sesssetup_and_X(struct smb_request *req)
1291 int sess_vuid;
1292 int smb_bufsize;
1293 DATA_BLOB lm_resp;
1294 DATA_BLOB nt_resp;
1295 DATA_BLOB plaintext_password;
1296 char *tmp;
1297 const char *user;
1298 fstring sub_user; /* Sanitised username for substituion */
1299 const char *domain;
1300 const char *native_os;
1301 const char *native_lanman;
1302 const char *primary_domain;
1303 struct auth_usersupplied_info *user_info = NULL;
1304 struct auth_serversupplied_info *server_info = NULL;
1305 struct auth_session_info *session_info = NULL;
1306 uint16 smb_flag2 = req->flags2;
1308 NTSTATUS nt_status;
1309 struct smbd_server_connection *sconn = req->sconn;
1311 bool doencrypt = sconn->smb1.negprot.encrypted_passwords;
1312 bool signing_allowed = false;
1313 bool signing_mandatory = false;
1315 START_PROFILE(SMBsesssetupX);
1317 ZERO_STRUCT(lm_resp);
1318 ZERO_STRUCT(nt_resp);
1319 ZERO_STRUCT(plaintext_password);
1321 DEBUG(3,("wct=%d flg2=0x%x\n", req->wct, req->flags2));
1323 if (req->flags2 & FLAGS2_SMB_SECURITY_SIGNATURES) {
1324 signing_allowed = true;
1326 if (req->flags2 & FLAGS2_SMB_SECURITY_SIGNATURES_REQUIRED) {
1327 signing_mandatory = true;
1331 * We can call srv_set_signing_negotiated() each time.
1332 * It finds out when it needs to turn into a noop
1333 * itself.
1335 srv_set_signing_negotiated(req->sconn,
1336 signing_allowed,
1337 signing_mandatory);
1339 /* a SPNEGO session setup has 12 command words, whereas a normal
1340 NT1 session setup has 13. See the cifs spec. */
1341 if (req->wct == 12 &&
1342 (req->flags2 & FLAGS2_EXTENDED_SECURITY)) {
1344 if (!sconn->smb1.negprot.spnego) {
1345 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt "
1346 "at SPNEGO session setup when it was not "
1347 "negotiated.\n"));
1348 reply_nterror(req, nt_status_squash(
1349 NT_STATUS_LOGON_FAILURE));
1350 END_PROFILE(SMBsesssetupX);
1351 return;
1354 if (SVAL(req->vwv+4, 0) == 0) {
1355 setup_new_vc_session(req->sconn);
1358 reply_sesssetup_and_X_spnego(req);
1359 END_PROFILE(SMBsesssetupX);
1360 return;
1363 smb_bufsize = SVAL(req->vwv+2, 0);
1365 if (get_Protocol() < PROTOCOL_NT1) {
1366 uint16 passlen1 = SVAL(req->vwv+7, 0);
1368 /* Never do NT status codes with protocols before NT1 as we
1369 * don't get client caps. */
1370 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1372 if ((passlen1 > MAX_PASS_LEN) || (passlen1 > req->buflen)) {
1373 reply_nterror(req, nt_status_squash(
1374 NT_STATUS_INVALID_PARAMETER));
1375 END_PROFILE(SMBsesssetupX);
1376 return;
1379 if (doencrypt) {
1380 lm_resp = data_blob(req->buf, passlen1);
1381 } else {
1382 plaintext_password = data_blob(req->buf, passlen1+1);
1383 /* Ensure null termination */
1384 plaintext_password.data[passlen1] = 0;
1387 srvstr_pull_req_talloc(talloc_tos(), req, &tmp,
1388 req->buf + passlen1, STR_TERMINATE);
1389 user = tmp ? tmp : "";
1391 domain = "";
1393 } else {
1394 uint16 passlen1 = SVAL(req->vwv+7, 0);
1395 uint16 passlen2 = SVAL(req->vwv+8, 0);
1396 enum remote_arch_types ra_type = get_remote_arch();
1397 const uint8_t *p = req->buf;
1398 const uint8_t *save_p = req->buf;
1399 uint16 byte_count;
1402 if(global_client_caps == 0) {
1403 global_client_caps = IVAL(req->vwv+11, 0);
1405 if (!(global_client_caps & CAP_STATUS32)) {
1406 remove_from_common_flags2(
1407 FLAGS2_32_BIT_ERROR_CODES);
1410 /* client_caps is used as final determination if
1411 * client is NT or Win95. This is needed to return
1412 * the correct error codes in some circumstances.
1415 if(ra_type == RA_WINNT || ra_type == RA_WIN2K ||
1416 ra_type == RA_WIN95) {
1417 if(!(global_client_caps & (CAP_NT_SMBS|
1418 CAP_STATUS32))) {
1419 set_remote_arch( RA_WIN95);
1424 if (!doencrypt) {
1425 /* both Win95 and WinNT stuff up the password
1426 * lengths for non-encrypting systems. Uggh.
1428 if passlen1==24 its a win95 system, and its setting
1429 the password length incorrectly. Luckily it still
1430 works with the default code because Win95 will null
1431 terminate the password anyway
1433 if passlen1>0 and passlen2>0 then maybe its a NT box
1434 and its setting passlen2 to some random value which
1435 really stuffs things up. we need to fix that one. */
1437 if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 &&
1438 passlen2 != 1) {
1439 passlen2 = 0;
1443 /* check for nasty tricks */
1444 if (passlen1 > MAX_PASS_LEN
1445 || passlen1 > smbreq_bufrem(req, p)) {
1446 reply_nterror(req, nt_status_squash(
1447 NT_STATUS_INVALID_PARAMETER));
1448 END_PROFILE(SMBsesssetupX);
1449 return;
1452 if (passlen2 > MAX_PASS_LEN
1453 || passlen2 > smbreq_bufrem(req, p+passlen1)) {
1454 reply_nterror(req, nt_status_squash(
1455 NT_STATUS_INVALID_PARAMETER));
1456 END_PROFILE(SMBsesssetupX);
1457 return;
1460 /* Save the lanman2 password and the NT md4 password. */
1462 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
1463 doencrypt = False;
1466 if (doencrypt) {
1467 lm_resp = data_blob(p, passlen1);
1468 nt_resp = data_blob(p+passlen1, passlen2);
1469 } else if (lp_security() != SEC_SHARE) {
1471 * In share level we should ignore any passwords, so
1472 * only read them if we're not.
1474 char *pass = NULL;
1475 bool unic= smb_flag2 & FLAGS2_UNICODE_STRINGS;
1477 if (unic && (passlen2 == 0) && passlen1) {
1478 /* Only a ascii plaintext password was sent. */
1479 (void)srvstr_pull_talloc(talloc_tos(),
1480 req->inbuf,
1481 req->flags2,
1482 &pass,
1483 req->buf,
1484 passlen1,
1485 STR_TERMINATE|STR_ASCII);
1486 } else {
1487 (void)srvstr_pull_talloc(talloc_tos(),
1488 req->inbuf,
1489 req->flags2,
1490 &pass,
1491 req->buf,
1492 unic ? passlen2 : passlen1,
1493 STR_TERMINATE);
1495 if (!pass) {
1496 reply_nterror(req, nt_status_squash(
1497 NT_STATUS_INVALID_PARAMETER));
1498 END_PROFILE(SMBsesssetupX);
1499 return;
1501 plaintext_password = data_blob(pass, strlen(pass)+1);
1504 p += passlen1 + passlen2;
1506 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1507 STR_TERMINATE);
1508 user = tmp ? tmp : "";
1510 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1511 STR_TERMINATE);
1512 domain = tmp ? tmp : "";
1514 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1515 STR_TERMINATE);
1516 native_os = tmp ? tmp : "";
1518 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1519 STR_TERMINATE);
1520 native_lanman = tmp ? tmp : "";
1522 /* not documented or decoded by Ethereal but there is one more
1523 * string in the extra bytes which is the same as the
1524 * PrimaryDomain when using extended security. Windows NT 4
1525 * and 2003 use this string to store the native lanman string.
1526 * Windows 9x does not include a string here at all so we have
1527 * to check if we have any extra bytes left */
1529 byte_count = SVAL(req->vwv+13, 0);
1530 if ( PTR_DIFF(p, save_p) < byte_count) {
1531 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1532 STR_TERMINATE);
1533 primary_domain = tmp ? tmp : "";
1534 } else {
1535 primary_domain = talloc_strdup(talloc_tos(), "null");
1538 DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s] "
1539 "PrimaryDomain=[%s]\n",
1540 domain, native_os, native_lanman, primary_domain));
1542 if ( ra_type == RA_WIN2K ) {
1543 if ( strlen(native_lanman) == 0 )
1544 ra_lanman_string( primary_domain );
1545 else
1546 ra_lanman_string( native_lanman );
1551 if (SVAL(req->vwv+4, 0) == 0) {
1552 setup_new_vc_session(req->sconn);
1555 DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n",
1556 domain, user, get_remote_machine_name()));
1558 if (*user) {
1559 if (sconn->smb1.negprot.spnego) {
1561 /* This has to be here, because this is a perfectly
1562 * valid behaviour for guest logons :-( */
1564 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt "
1565 "at 'normal' session setup after "
1566 "negotiating spnego.\n"));
1567 reply_nterror(req, nt_status_squash(
1568 NT_STATUS_LOGON_FAILURE));
1569 END_PROFILE(SMBsesssetupX);
1570 return;
1572 fstrcpy(sub_user, user);
1573 } else {
1574 fstrcpy(sub_user, "");
1577 sub_set_smb_name(sub_user);
1579 reload_services(sconn, conn_snum_used, true);
1581 if (lp_security() == SEC_SHARE) {
1582 char *sub_user_mapped = NULL;
1583 /* In share level we should ignore any passwords */
1585 data_blob_free(&lm_resp);
1586 data_blob_free(&nt_resp);
1587 data_blob_clear_free(&plaintext_password);
1589 (void)map_username(talloc_tos(), sub_user, &sub_user_mapped);
1590 if (!sub_user_mapped) {
1591 reply_nterror(req, NT_STATUS_NO_MEMORY);
1592 END_PROFILE(SMBsesssetupX);
1593 return;
1595 fstrcpy(sub_user, sub_user_mapped);
1596 add_session_user(sconn, sub_user);
1597 add_session_workgroup(sconn, domain);
1598 /* Then force it to null for the benfit of the code below */
1599 user = "";
1602 if (!*user) {
1604 nt_status = check_guest_password(sconn->remote_address, &server_info);
1606 } else if (doencrypt) {
1607 struct auth_context *negprot_auth_context = NULL;
1608 negprot_auth_context = sconn->smb1.negprot.auth_context;
1609 if (!negprot_auth_context) {
1610 DEBUG(0, ("reply_sesssetup_and_X: Attempted encrypted "
1611 "session setup without negprot denied!\n"));
1612 reply_nterror(req, nt_status_squash(
1613 NT_STATUS_LOGON_FAILURE));
1614 END_PROFILE(SMBsesssetupX);
1615 return;
1617 nt_status = make_user_info_for_reply_enc(&user_info, user,
1618 domain,
1619 sconn->remote_address,
1620 lm_resp, nt_resp);
1621 if (NT_STATUS_IS_OK(nt_status)) {
1622 nt_status = negprot_auth_context->check_ntlm_password(
1623 negprot_auth_context,
1624 user_info,
1625 &server_info);
1627 } else {
1628 struct auth_context *plaintext_auth_context = NULL;
1630 nt_status = make_auth_context_subsystem(
1631 talloc_tos(), &plaintext_auth_context);
1633 if (NT_STATUS_IS_OK(nt_status)) {
1634 uint8_t chal[8];
1636 plaintext_auth_context->get_ntlm_challenge(
1637 plaintext_auth_context, chal);
1639 if (!make_user_info_for_reply(&user_info,
1640 user, domain,
1641 sconn->remote_address,
1642 chal,
1643 plaintext_password)) {
1644 nt_status = NT_STATUS_NO_MEMORY;
1647 if (NT_STATUS_IS_OK(nt_status)) {
1648 nt_status = plaintext_auth_context->check_ntlm_password(
1649 plaintext_auth_context,
1650 user_info,
1651 &server_info);
1653 TALLOC_FREE(plaintext_auth_context);
1658 free_user_info(&user_info);
1660 if (!NT_STATUS_IS_OK(nt_status)) {
1661 nt_status = do_map_to_guest_server_info(nt_status, &server_info,
1662 user, domain);
1665 if (!NT_STATUS_IS_OK(nt_status)) {
1666 data_blob_free(&nt_resp);
1667 data_blob_free(&lm_resp);
1668 data_blob_clear_free(&plaintext_password);
1669 reply_nterror(req, nt_status_squash(nt_status));
1670 END_PROFILE(SMBsesssetupX);
1671 return;
1674 nt_status = create_local_token(req, server_info, NULL, sub_user, &session_info);
1675 TALLOC_FREE(server_info);
1677 if (!NT_STATUS_IS_OK(nt_status)) {
1678 DEBUG(10, ("create_local_token failed: %s\n",
1679 nt_errstr(nt_status)));
1680 data_blob_free(&nt_resp);
1681 data_blob_free(&lm_resp);
1682 data_blob_clear_free(&plaintext_password);
1683 reply_nterror(req, nt_status_squash(nt_status));
1684 END_PROFILE(SMBsesssetupX);
1685 return;
1688 data_blob_clear_free(&plaintext_password);
1690 /* it's ok - setup a reply */
1691 reply_outbuf(req, 3, 0);
1692 if (get_Protocol() >= PROTOCOL_NT1) {
1693 push_signature(&req->outbuf);
1694 /* perhaps grab OS version here?? */
1697 if (security_session_user_level(session_info, NULL) < SECURITY_USER) {
1698 SSVAL(req->outbuf,smb_vwv2,1);
1701 /* register the name and uid as being validated, so further connections
1702 to a uid can get through without a password, on the same VC */
1704 if (lp_security() == SEC_SHARE) {
1705 sess_vuid = UID_FIELD_INVALID;
1706 TALLOC_FREE(session_info);
1707 } else {
1708 /* Ignore the initial vuid. */
1709 sess_vuid = register_initial_vuid(sconn);
1710 if (sess_vuid == UID_FIELD_INVALID) {
1711 data_blob_free(&nt_resp);
1712 data_blob_free(&lm_resp);
1713 reply_nterror(req, nt_status_squash(
1714 NT_STATUS_LOGON_FAILURE));
1715 END_PROFILE(SMBsesssetupX);
1716 return;
1718 /* register_existing_vuid keeps the session_info */
1719 sess_vuid = register_existing_vuid(sconn, sess_vuid,
1720 session_info,
1721 nt_resp.data ? nt_resp : lm_resp);
1722 if (sess_vuid == UID_FIELD_INVALID) {
1723 data_blob_free(&nt_resp);
1724 data_blob_free(&lm_resp);
1725 reply_nterror(req, nt_status_squash(
1726 NT_STATUS_LOGON_FAILURE));
1727 END_PROFILE(SMBsesssetupX);
1728 return;
1731 /* current_user_info is changed on new vuid */
1732 reload_services(sconn, conn_snum_used, true);
1735 data_blob_free(&nt_resp);
1736 data_blob_free(&lm_resp);
1738 SSVAL(req->outbuf,smb_uid,sess_vuid);
1739 SSVAL(discard_const_p(char, req->inbuf),smb_uid,sess_vuid);
1740 req->vuid = sess_vuid;
1742 if (!sconn->smb1.sessions.done_sesssetup) {
1743 sconn->smb1.sessions.max_send =
1744 MIN(sconn->smb1.sessions.max_send,smb_bufsize);
1746 sconn->smb1.sessions.done_sesssetup = true;
1748 END_PROFILE(SMBsesssetupX);
1749 chain_reply(req);
1750 return;