[GLUE] Rsync SAMBA_3_0 SVN r25598 in order to create the v3-0-test branch.
[Samba.git] / source / smbd / sesssetup.c
blob05a5962056ced4dcf3245d79ef70ad42182035bc
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
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "includes.h"
26 extern struct auth_context *negprot_global_auth_context;
27 extern BOOL global_encrypted_passwords_negotiated;
28 extern BOOL global_spnego_negotiated;
29 extern enum protocol_types Protocol;
30 extern int max_send;
32 uint32 global_client_caps = 0;
35 on a logon error possibly map the error to success if "map to guest"
36 is set approriately
38 static NTSTATUS do_map_to_guest(NTSTATUS status, auth_serversupplied_info **server_info,
39 const char *user, const char *domain)
41 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
42 if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) ||
43 (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) {
44 DEBUG(3,("No such user %s [%s] - using guest account\n",
45 user, domain));
46 status = make_server_info_guest(server_info);
50 if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
51 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) {
52 DEBUG(3,("Registered username %s for guest access\n",user));
53 status = make_server_info_guest(server_info);
57 return status;
60 /****************************************************************************
61 Add the standard 'Samba' signature to the end of the session setup.
62 ****************************************************************************/
64 static int add_signature(char *outbuf, char *p)
66 char *start = p;
67 fstring lanman;
69 fstr_sprintf( lanman, "Samba %s", SAMBA_VERSION_STRING);
71 p += srvstr_push(outbuf, p, "Unix", -1, STR_TERMINATE);
72 p += srvstr_push(outbuf, p, lanman, -1, STR_TERMINATE);
73 p += srvstr_push(outbuf, p, lp_workgroup(), -1, STR_TERMINATE);
75 return PTR_DIFF(p, start);
78 /****************************************************************************
79 Start the signing engine if needed. Don't fail signing here.
80 ****************************************************************************/
82 static void sessionsetup_start_signing_engine(const auth_serversupplied_info *server_info, char *inbuf)
84 if (!server_info->guest && !srv_signing_started()) {
85 /* We need to start the signing engine
86 * here but a W2K client sends the old
87 * "BSRSPYL " signature instead of the
88 * correct one. Subsequent packets will
89 * be correct.
91 srv_check_sign_mac(inbuf, False);
95 /****************************************************************************
96 Send a security blob via a session setup reply.
97 ****************************************************************************/
99 static BOOL reply_sesssetup_blob(connection_struct *conn, char *outbuf,
100 DATA_BLOB blob, NTSTATUS nt_status)
102 char *p;
104 if (!NT_STATUS_IS_OK(nt_status) && !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
105 ERROR_NT(nt_status_squash(nt_status));
106 } else {
107 set_message(outbuf,4,0,True);
109 nt_status = nt_status_squash(nt_status);
110 SIVAL(outbuf, smb_rcls, NT_STATUS_V(nt_status));
111 SSVAL(outbuf, smb_vwv0, 0xFF); /* no chaining possible */
112 SSVAL(outbuf, smb_vwv3, blob.length);
113 p = smb_buf(outbuf);
115 /* should we cap this? */
116 memcpy(p, blob.data, blob.length);
117 p += blob.length;
119 p += add_signature( outbuf, p );
121 set_message_end(outbuf,p);
124 show_msg(outbuf);
125 return send_smb(smbd_server_fd(),outbuf);
128 /****************************************************************************
129 Do a 'guest' logon, getting back the
130 ****************************************************************************/
132 static NTSTATUS check_guest_password(auth_serversupplied_info **server_info)
134 struct auth_context *auth_context;
135 auth_usersupplied_info *user_info = NULL;
137 NTSTATUS nt_status;
138 unsigned char chal[8];
140 ZERO_STRUCT(chal);
142 DEBUG(3,("Got anonymous request\n"));
144 if (!NT_STATUS_IS_OK(nt_status = make_auth_context_fixed(&auth_context, chal))) {
145 return nt_status;
148 if (!make_user_info_guest(&user_info)) {
149 (auth_context->free)(&auth_context);
150 return NT_STATUS_NO_MEMORY;
153 nt_status = auth_context->check_ntlm_password(auth_context, user_info, server_info);
154 (auth_context->free)(&auth_context);
155 free_user_info(&user_info);
156 return nt_status;
160 #ifdef HAVE_KRB5
162 #if 0
163 /* Experiment that failed. See "only happens with a KDC" comment below. */
164 /****************************************************************************
165 Cerate a clock skew error blob for a Windows client.
166 ****************************************************************************/
168 static BOOL make_krb5_skew_error(DATA_BLOB *pblob_out)
170 krb5_context context = NULL;
171 krb5_error_code kerr = 0;
172 krb5_data reply;
173 krb5_principal host_princ = NULL;
174 char *host_princ_s = NULL;
175 BOOL ret = False;
177 *pblob_out = data_blob(NULL,0);
179 initialize_krb5_error_table();
180 kerr = krb5_init_context(&context);
181 if (kerr) {
182 return False;
184 /* Create server principal. */
185 asprintf(&host_princ_s, "%s$@%s", global_myname(), lp_realm());
186 if (!host_princ_s) {
187 goto out;
189 strlower_m(host_princ_s);
191 kerr = smb_krb5_parse_name(context, host_princ_s, &host_princ);
192 if (kerr) {
193 DEBUG(10,("make_krb5_skew_error: smb_krb5_parse_name failed for name %s: Error %s\n",
194 host_princ_s, error_message(kerr) ));
195 goto out;
198 kerr = smb_krb5_mk_error(context, KRB5KRB_AP_ERR_SKEW, host_princ, &reply);
199 if (kerr) {
200 DEBUG(10,("make_krb5_skew_error: smb_krb5_mk_error failed: Error %s\n",
201 error_message(kerr) ));
202 goto out;
205 *pblob_out = data_blob(reply.data, reply.length);
206 kerberos_free_data_contents(context,&reply);
207 ret = True;
209 out:
211 if (host_princ_s) {
212 SAFE_FREE(host_princ_s);
214 if (host_princ) {
215 krb5_free_principal(context, host_princ);
217 krb5_free_context(context);
218 return ret;
220 #endif
222 /****************************************************************************
223 Reply to a session setup spnego negotiate packet for kerberos.
224 ****************************************************************************/
226 static int reply_spnego_kerberos(connection_struct *conn,
227 char *inbuf, char *outbuf,
228 int length, int bufsize,
229 DATA_BLOB *secblob,
230 BOOL *p_invalidate_vuid)
232 TALLOC_CTX *mem_ctx;
233 DATA_BLOB ticket;
234 char *client, *p, *domain;
235 fstring netbios_domain_name;
236 struct passwd *pw;
237 fstring user;
238 int sess_vuid;
239 NTSTATUS ret;
240 PAC_DATA *pac_data;
241 DATA_BLOB ap_rep, ap_rep_wrapped, response;
242 auth_serversupplied_info *server_info = NULL;
243 DATA_BLOB session_key = data_blob(NULL, 0);
244 uint8 tok_id[2];
245 DATA_BLOB nullblob = data_blob(NULL, 0);
246 fstring real_username;
247 BOOL map_domainuser_to_guest = False;
248 BOOL username_was_mapped;
249 PAC_LOGON_INFO *logon_info = NULL;
251 ZERO_STRUCT(ticket);
252 ZERO_STRUCT(pac_data);
253 ZERO_STRUCT(ap_rep);
254 ZERO_STRUCT(ap_rep_wrapped);
255 ZERO_STRUCT(response);
257 /* Normally we will always invalidate the intermediate vuid. */
258 *p_invalidate_vuid = True;
260 mem_ctx = talloc_init("reply_spnego_kerberos");
261 if (mem_ctx == NULL) {
262 return ERROR_NT(nt_status_squash(NT_STATUS_NO_MEMORY));
265 if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) {
266 talloc_destroy(mem_ctx);
267 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
270 ret = ads_verify_ticket(mem_ctx, lp_realm(), 0, &ticket, &client, &pac_data, &ap_rep, &session_key);
272 data_blob_free(&ticket);
274 if (!NT_STATUS_IS_OK(ret)) {
275 #if 0
276 /* Experiment that failed. 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 NT_STATUS_MORE_PROCESSING_REQUIRED
282 * with a negTokenTarg blob containing an krb5_error struct ASN1 encoded
283 * containing KRB5KRB_AP_ERR_SKEW. The client then fixes its
284 * clock and continues rather than giving an error. JRA.
285 * -- Looks like this only happens with a KDC. JRA.
288 BOOL ok = make_krb5_skew_error(&ap_rep);
289 if (!ok) {
290 talloc_destroy(mem_ctx);
291 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
293 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep, TOK_ID_KRB_ERROR);
294 response = spnego_gen_auth_response(&ap_rep_wrapped, ret, OID_KERBEROS5_OLD);
295 reply_sesssetup_blob(conn, outbuf, response, NT_STATUS_MORE_PROCESSING_REQUIRED);
298 * In this one case we don't invalidate the intermediate vuid.
299 * as we're expecting the client to re-use it for the next
300 * sessionsetupX packet. JRA.
303 *p_invalidate_vuid = False;
305 data_blob_free(&ap_rep);
306 data_blob_free(&ap_rep_wrapped);
307 data_blob_free(&response);
308 talloc_destroy(mem_ctx);
309 return -1; /* already replied */
311 #else
312 if (!NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
313 ret = NT_STATUS_LOGON_FAILURE;
315 #endif
316 DEBUG(1,("Failed to verify incoming ticket with error %s!\n", nt_errstr(ret)));
317 talloc_destroy(mem_ctx);
318 return ERROR_NT(nt_status_squash(ret));
321 DEBUG(3,("Ticket name is [%s]\n", client));
323 p = strchr_m(client, '@');
324 if (!p) {
325 DEBUG(3,("Doesn't look like a valid principal\n"));
326 data_blob_free(&ap_rep);
327 data_blob_free(&session_key);
328 SAFE_FREE(client);
329 talloc_destroy(mem_ctx);
330 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
333 *p = 0;
335 /* save the PAC data if we have it */
337 if (pac_data) {
338 logon_info = get_logon_info_from_pac(pac_data);
339 if (logon_info) {
340 netsamlogon_cache_store( client, &logon_info->info3 );
344 if (!strequal(p+1, lp_realm())) {
345 DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1));
346 if (!lp_allow_trusted_domains()) {
347 data_blob_free(&ap_rep);
348 data_blob_free(&session_key);
349 SAFE_FREE(client);
350 talloc_destroy(mem_ctx);
351 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
355 /* this gives a fully qualified user name (ie. with full realm).
356 that leads to very long usernames, but what else can we do? */
358 domain = p+1;
360 if (logon_info && logon_info->info3.hdr_logon_dom.uni_str_len) {
362 unistr2_to_ascii(netbios_domain_name, &logon_info->info3.uni_logon_dom, -1);
363 domain = netbios_domain_name;
364 DEBUG(10, ("Mapped to [%s] (using PAC)\n", domain));
366 } else {
368 /* If we have winbind running, we can (and must) shorten the
369 username by using the short netbios name. Otherwise we will
370 have inconsistent user names. With Kerberos, we get the
371 fully qualified realm, with ntlmssp we get the short
372 name. And even w2k3 does use ntlmssp if you for example
373 connect to an ip address. */
375 struct winbindd_request wb_request;
376 struct winbindd_response wb_response;
377 NSS_STATUS wb_result;
379 ZERO_STRUCT(wb_request);
380 ZERO_STRUCT(wb_response);
382 DEBUG(10, ("Mapping [%s] to short name\n", domain));
384 fstrcpy(wb_request.domain_name, domain);
386 wb_result = winbindd_request_response(WINBINDD_DOMAIN_INFO,
387 &wb_request, &wb_response);
389 if (wb_result == NSS_STATUS_SUCCESS) {
391 fstrcpy(netbios_domain_name,
392 wb_response.data.domain_info.name);
393 domain = netbios_domain_name;
395 DEBUG(10, ("Mapped to [%s] (using Winbind)\n", domain));
396 } else {
397 DEBUG(3, ("Could not find short name -- winbind "
398 "not running?\n"));
402 fstr_sprintf(user, "%s%c%s", domain, *lp_winbind_separator(), client);
404 /* lookup the passwd struct, create a new user if necessary */
406 username_was_mapped = map_username( user );
408 pw = smb_getpwnam( mem_ctx, user, real_username, True );
410 if (pw) {
411 /* if a real user check pam account restrictions */
412 /* only really perfomed if "obey pam restriction" is true */
413 /* do this before an eventual mappign to guest occurs */
414 ret = smb_pam_accountcheck(pw->pw_name);
415 if ( !NT_STATUS_IS_OK(ret)) {
416 DEBUG(1, ("PAM account restriction prevents user login\n"));
417 data_blob_free(&ap_rep);
418 data_blob_free(&session_key);
419 TALLOC_FREE(mem_ctx);
420 return ERROR_NT(nt_status_squash(ret));
424 if (!pw) {
426 /* this was originally the behavior of Samba 2.2, if a user
427 did not have a local uid but has been authenticated, then
428 map them to a guest account */
430 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID){
431 map_domainuser_to_guest = True;
432 fstrcpy(user,lp_guestaccount());
433 pw = smb_getpwnam( mem_ctx, user, real_username, True );
436 /* extra sanity check that the guest account is valid */
438 if ( !pw ) {
439 DEBUG(1,("Username %s is invalid on this system\n", user));
440 SAFE_FREE(client);
441 data_blob_free(&ap_rep);
442 data_blob_free(&session_key);
443 TALLOC_FREE(mem_ctx);
444 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
448 /* setup the string used by %U */
450 sub_set_smb_name( real_username );
451 reload_services(True);
453 if ( map_domainuser_to_guest ) {
454 make_server_info_guest(&server_info);
455 } else if (logon_info) {
456 /* pass the unmapped username here since map_username()
457 will be called again from inside make_server_info_info3() */
459 ret = make_server_info_info3(mem_ctx, client, domain,
460 &server_info, &logon_info->info3);
461 if ( !NT_STATUS_IS_OK(ret) ) {
462 DEBUG(1,("make_server_info_info3 failed: %s!\n",
463 nt_errstr(ret)));
464 SAFE_FREE(client);
465 data_blob_free(&ap_rep);
466 data_blob_free(&session_key);
467 TALLOC_FREE(mem_ctx);
468 return ERROR_NT(nt_status_squash(ret));
471 } else {
472 ret = make_server_info_pw(&server_info, real_username, pw);
474 if ( !NT_STATUS_IS_OK(ret) ) {
475 DEBUG(1,("make_server_info_pw failed: %s!\n",
476 nt_errstr(ret)));
477 SAFE_FREE(client);
478 data_blob_free(&ap_rep);
479 data_blob_free(&session_key);
480 TALLOC_FREE(mem_ctx);
481 return ERROR_NT(nt_status_squash(ret));
484 /* make_server_info_pw does not set the domain. Without this
485 * we end up with the local netbios name in substitutions for
486 * %D. */
488 if (server_info->sam_account != NULL) {
489 pdb_set_domain(server_info->sam_account, domain, PDB_SET);
493 server_info->was_mapped |= username_was_mapped;
495 /* we need to build the token for the user. make_server_info_guest()
496 already does this */
498 if ( !server_info->ptok ) {
499 ret = create_local_token( server_info );
500 if ( !NT_STATUS_IS_OK(ret) ) {
501 SAFE_FREE(client);
502 data_blob_free(&ap_rep);
503 data_blob_free(&session_key);
504 TALLOC_FREE( mem_ctx );
505 TALLOC_FREE( server_info );
506 return ERROR_NT(nt_status_squash(ret));
510 /* register_vuid keeps the server info */
511 /* register_vuid takes ownership of session_key, no need to free after this.
512 A better interface would copy it.... */
513 sess_vuid = register_vuid(server_info, session_key, nullblob, client);
515 SAFE_FREE(client);
517 if (sess_vuid == UID_FIELD_INVALID ) {
518 ret = NT_STATUS_LOGON_FAILURE;
519 } else {
520 /* current_user_info is changed on new vuid */
521 reload_services( True );
523 set_message(outbuf,4,0,True);
524 SSVAL(outbuf, smb_vwv3, 0);
526 if (server_info->guest) {
527 SSVAL(outbuf,smb_vwv2,1);
530 SSVAL(outbuf, smb_uid, sess_vuid);
532 sessionsetup_start_signing_engine(server_info, inbuf);
535 /* wrap that up in a nice GSS-API wrapping */
536 if (NT_STATUS_IS_OK(ret)) {
537 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep, TOK_ID_KRB_AP_REP);
538 } else {
539 ap_rep_wrapped = data_blob(NULL, 0);
541 response = spnego_gen_auth_response(&ap_rep_wrapped, ret, OID_KERBEROS5_OLD);
542 reply_sesssetup_blob(conn, outbuf, response, ret);
544 data_blob_free(&ap_rep);
545 data_blob_free(&ap_rep_wrapped);
546 data_blob_free(&response);
547 TALLOC_FREE(mem_ctx);
549 return -1; /* already replied */
551 #endif
553 /****************************************************************************
554 Send a session setup reply, wrapped in SPNEGO.
555 Get vuid and check first.
556 End the NTLMSSP exchange context if we are OK/complete fail
557 This should be split into two functions, one to handle each
558 leg of the NTLM auth steps.
559 ***************************************************************************/
561 static BOOL reply_spnego_ntlmssp(connection_struct *conn, char *inbuf, char *outbuf,
562 uint16 vuid,
563 AUTH_NTLMSSP_STATE **auth_ntlmssp_state,
564 DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status,
565 BOOL wrap)
567 BOOL ret;
568 DATA_BLOB response;
569 struct auth_serversupplied_info *server_info = NULL;
571 if (NT_STATUS_IS_OK(nt_status)) {
572 server_info = (*auth_ntlmssp_state)->server_info;
573 } else {
574 nt_status = do_map_to_guest(nt_status,
575 &server_info,
576 (*auth_ntlmssp_state)->ntlmssp_state->user,
577 (*auth_ntlmssp_state)->ntlmssp_state->domain);
580 if (NT_STATUS_IS_OK(nt_status)) {
581 int sess_vuid;
582 DATA_BLOB nullblob = data_blob(NULL, 0);
583 DATA_BLOB session_key = data_blob((*auth_ntlmssp_state)->ntlmssp_state->session_key.data, (*auth_ntlmssp_state)->ntlmssp_state->session_key.length);
585 /* register_vuid keeps the server info */
586 sess_vuid = register_vuid(server_info, session_key, nullblob, (*auth_ntlmssp_state)->ntlmssp_state->user);
587 (*auth_ntlmssp_state)->server_info = NULL;
589 if (sess_vuid == UID_FIELD_INVALID ) {
590 nt_status = NT_STATUS_LOGON_FAILURE;
591 } else {
593 /* current_user_info is changed on new vuid */
594 reload_services( True );
596 set_message(outbuf,4,0,True);
597 SSVAL(outbuf, smb_vwv3, 0);
599 if (server_info->guest) {
600 SSVAL(outbuf,smb_vwv2,1);
603 SSVAL(outbuf,smb_uid,sess_vuid);
605 sessionsetup_start_signing_engine(server_info, inbuf);
609 if (wrap) {
610 response = spnego_gen_auth_response(ntlmssp_blob, nt_status, OID_NTLMSSP);
611 } else {
612 response = *ntlmssp_blob;
615 ret = reply_sesssetup_blob(conn, outbuf, response, nt_status);
616 if (wrap) {
617 data_blob_free(&response);
620 /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
621 and the other end, that we are not finished yet. */
623 if (!ret || !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
624 /* NB. This is *NOT* an error case. JRA */
625 auth_ntlmssp_end(auth_ntlmssp_state);
626 /* Kill the intermediate vuid */
627 invalidate_vuid(vuid);
630 return ret;
633 /****************************************************************************
634 Is this a krb5 mechanism ?
635 ****************************************************************************/
637 static NTSTATUS parse_spnego_mechanisms(DATA_BLOB blob_in, DATA_BLOB *pblob_out, BOOL *p_is_krb5)
639 char *OIDs[ASN1_MAX_OIDS];
640 int i;
642 *p_is_krb5 = False;
644 /* parse out the OIDs and the first sec blob */
645 if (!parse_negTokenTarg(blob_in, OIDs, pblob_out)) {
646 return NT_STATUS_LOGON_FAILURE;
649 /* only look at the first OID for determining the mechToken --
650 accoirding to RFC2478, we should choose the one we want
651 and renegotiate, but i smell a client bug here..
653 Problem observed when connecting to a member (samba box)
654 of an AD domain as a user in a Samba domain. Samba member
655 server sent back krb5/mskrb5/ntlmssp as mechtypes, but the
656 client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an
657 NTLMSSP mechtoken. --jerry */
659 #ifdef HAVE_KRB5
660 if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||
661 strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
662 *p_is_krb5 = True;
664 #endif
666 for (i=0;OIDs[i];i++) {
667 DEBUG(5,("parse_spnego_mechanisms: Got OID %s\n", OIDs[i]));
668 free(OIDs[i]);
670 return NT_STATUS_OK;
673 /****************************************************************************
674 Reply to a session setup spnego negotiate packet.
675 ****************************************************************************/
677 static int reply_spnego_negotiate(connection_struct *conn,
678 char *inbuf,
679 char *outbuf,
680 uint16 vuid,
681 int length, int bufsize,
682 DATA_BLOB blob1,
683 AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
685 DATA_BLOB secblob;
686 DATA_BLOB chal;
687 BOOL got_kerberos_mechanism = False;
688 NTSTATUS status;
690 status = parse_spnego_mechanisms(blob1, &secblob, &got_kerberos_mechanism);
691 if (!NT_STATUS_IS_OK(status)) {
692 /* Kill the intermediate vuid */
693 invalidate_vuid(vuid);
694 return ERROR_NT(nt_status_squash(status));
697 DEBUG(3,("reply_spnego_negotiate: Got secblob of size %lu\n", (unsigned long)secblob.length));
699 #ifdef HAVE_KRB5
700 if ( got_kerberos_mechanism && ((lp_security()==SEC_ADS) || lp_use_kerberos_keytab()) ) {
701 BOOL destroy_vuid = True;
702 int ret = reply_spnego_kerberos(conn, inbuf, outbuf,
703 length, bufsize, &secblob, &destroy_vuid);
704 data_blob_free(&secblob);
705 if (destroy_vuid) {
706 /* Kill the intermediate vuid */
707 invalidate_vuid(vuid);
709 return ret;
711 #endif
713 if (*auth_ntlmssp_state) {
714 auth_ntlmssp_end(auth_ntlmssp_state);
717 status = auth_ntlmssp_start(auth_ntlmssp_state);
718 if (!NT_STATUS_IS_OK(status)) {
719 /* Kill the intermediate vuid */
720 invalidate_vuid(vuid);
721 return ERROR_NT(nt_status_squash(status));
724 status = auth_ntlmssp_update(*auth_ntlmssp_state,
725 secblob, &chal);
727 data_blob_free(&secblob);
729 reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid, auth_ntlmssp_state,
730 &chal, status, True);
732 data_blob_free(&chal);
734 /* already replied */
735 return -1;
738 /****************************************************************************
739 Reply to a session setup spnego auth packet.
740 ****************************************************************************/
742 static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
743 uint16 vuid,
744 int length, int bufsize,
745 DATA_BLOB blob1,
746 AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
748 DATA_BLOB auth = data_blob(NULL,0);
749 DATA_BLOB auth_reply = data_blob(NULL,0);
750 DATA_BLOB secblob = data_blob(NULL,0);
751 NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
753 if (!spnego_parse_auth(blob1, &auth)) {
754 #if 0
755 file_save("auth.dat", blob1.data, blob1.length);
756 #endif
757 /* Kill the intermediate vuid */
758 invalidate_vuid(vuid);
760 return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
763 if (auth.data[0] == ASN1_APPLICATION(0)) {
764 /* Might be a second negTokenTarg packet */
766 BOOL got_krb5_mechanism = False;
767 status = parse_spnego_mechanisms(auth, &secblob, &got_krb5_mechanism);
768 if (NT_STATUS_IS_OK(status)) {
769 DEBUG(3,("reply_spnego_auth: Got secblob of size %lu\n", (unsigned long)secblob.length));
770 #ifdef HAVE_KRB5
771 if ( got_krb5_mechanism && ((lp_security()==SEC_ADS) || lp_use_kerberos_keytab()) ) {
772 BOOL destroy_vuid = True;
773 int ret = reply_spnego_kerberos(conn, inbuf, outbuf,
774 length, bufsize, &secblob, &destroy_vuid);
775 data_blob_free(&secblob);
776 data_blob_free(&auth);
777 if (destroy_vuid) {
778 /* Kill the intermediate vuid */
779 invalidate_vuid(vuid);
781 return ret;
783 #endif
787 /* If we get here it wasn't a negTokenTarg auth packet. */
788 data_blob_free(&secblob);
790 if (!*auth_ntlmssp_state) {
791 /* Kill the intermediate vuid */
792 invalidate_vuid(vuid);
794 /* auth before negotiatiate? */
795 return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
798 status = auth_ntlmssp_update(*auth_ntlmssp_state,
799 auth, &auth_reply);
801 data_blob_free(&auth);
803 reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid,
804 auth_ntlmssp_state,
805 &auth_reply, status, True);
807 data_blob_free(&auth_reply);
809 /* and tell smbd that we have already replied to this packet */
810 return -1;
813 /****************************************************************************
814 List to store partial SPNEGO auth fragments.
815 ****************************************************************************/
817 static struct pending_auth_data *pd_list;
819 /****************************************************************************
820 Delete an entry on the list.
821 ****************************************************************************/
823 static void delete_partial_auth(struct pending_auth_data *pad)
825 if (!pad) {
826 return;
828 DLIST_REMOVE(pd_list, pad);
829 data_blob_free(&pad->partial_data);
830 SAFE_FREE(pad);
833 /****************************************************************************
834 Search for a partial SPNEGO auth fragment matching an smbpid.
835 ****************************************************************************/
837 static struct pending_auth_data *get_pending_auth_data(uint16 smbpid)
839 struct pending_auth_data *pad;
841 for (pad = pd_list; pad; pad = pad->next) {
842 if (pad->smbpid == smbpid) {
843 break;
846 return pad;
849 /****************************************************************************
850 Check the size of an SPNEGO blob. If we need more return NT_STATUS_MORE_PROCESSING_REQUIRED,
851 else return NT_STATUS_OK. Don't allow the blob to be more than 64k.
852 ****************************************************************************/
854 static NTSTATUS check_spnego_blob_complete(uint16 smbpid, uint16 vuid, DATA_BLOB *pblob)
856 struct pending_auth_data *pad = NULL;
857 ASN1_DATA data;
858 size_t needed_len = 0;
860 pad = get_pending_auth_data(smbpid);
862 /* Ensure we have some data. */
863 if (pblob->length == 0) {
864 /* Caller can cope. */
865 DEBUG(2,("check_spnego_blob_complete: zero blob length !\n"));
866 delete_partial_auth(pad);
867 return NT_STATUS_OK;
870 /* Were we waiting for more data ? */
871 if (pad) {
872 DATA_BLOB tmp_blob;
873 size_t copy_len = MIN(65536, pblob->length);
875 /* Integer wrap paranoia.... */
877 if (pad->partial_data.length + copy_len < pad->partial_data.length ||
878 pad->partial_data.length + copy_len < copy_len) {
880 DEBUG(2,("check_spnego_blob_complete: integer wrap "
881 "pad->partial_data.length = %u, "
882 "copy_len = %u\n",
883 (unsigned int)pad->partial_data.length,
884 (unsigned int)copy_len ));
886 delete_partial_auth(pad);
887 return NT_STATUS_INVALID_PARAMETER;
890 DEBUG(10,("check_spnego_blob_complete: "
891 "pad->partial_data.length = %u, "
892 "pad->needed_len = %u, "
893 "copy_len = %u, "
894 "pblob->length = %u,\n",
895 (unsigned int)pad->partial_data.length,
896 (unsigned int)pad->needed_len,
897 (unsigned int)copy_len,
898 (unsigned int)pblob->length ));
900 tmp_blob = data_blob(NULL,
901 pad->partial_data.length + copy_len);
903 /* Concatenate the two (up to copy_len) bytes. */
904 memcpy(tmp_blob.data,
905 pad->partial_data.data,
906 pad->partial_data.length);
907 memcpy(tmp_blob.data + pad->partial_data.length,
908 pblob->data,
909 copy_len);
911 /* Replace the partial data. */
912 data_blob_free(&pad->partial_data);
913 pad->partial_data = tmp_blob;
914 ZERO_STRUCT(tmp_blob);
916 /* Are we done ? */
917 if (pblob->length >= pad->needed_len) {
918 /* Yes, replace pblob. */
919 data_blob_free(pblob);
920 *pblob = pad->partial_data;
921 ZERO_STRUCT(pad->partial_data);
922 delete_partial_auth(pad);
923 return NT_STATUS_OK;
926 /* Still need more data. */
927 pad->needed_len -= copy_len;
928 return NT_STATUS_MORE_PROCESSING_REQUIRED;
931 if ((pblob->data[0] != ASN1_APPLICATION(0)) &&
932 (pblob->data[0] != ASN1_CONTEXT(1))) {
933 /* Not something we can determine the
934 * length of.
936 return NT_STATUS_OK;
939 /* This is a new SPNEGO sessionsetup - see if
940 * the data given in this blob is enough.
943 asn1_load(&data, *pblob);
944 asn1_start_tag(&data, pblob->data[0]);
945 if (data.has_error || data.nesting == NULL) {
946 asn1_free(&data);
947 /* Let caller catch. */
948 return NT_STATUS_OK;
951 /* Integer wrap paranoia.... */
953 if (data.nesting->taglen + data.nesting->start < data.nesting->taglen ||
954 data.nesting->taglen + data.nesting->start < data.nesting->start) {
956 DEBUG(2,("check_spnego_blob_complete: integer wrap "
957 "data.nesting->taglen = %u, "
958 "data.nesting->start = %u\n",
959 (unsigned int)data.nesting->taglen,
960 (unsigned int)data.nesting->start ));
962 asn1_free(&data);
963 return NT_STATUS_INVALID_PARAMETER;
966 /* Total length of the needed asn1 is the tag length
967 * plus the current offset. */
969 needed_len = data.nesting->taglen + data.nesting->start;
970 asn1_free(&data);
972 DEBUG(10,("check_spnego_blob_complete: needed_len = %u, "
973 "pblob->length = %u\n",
974 (unsigned int)needed_len,
975 (unsigned int)pblob->length ));
977 if (needed_len <= pblob->length) {
978 /* Nothing to do - blob is complete. */
979 return NT_STATUS_OK;
982 /* Refuse the blob if it's bigger than 64k. */
983 if (needed_len > 65536) {
984 DEBUG(2,("check_spnego_blob_complete: needed_len too large (%u)\n",
985 (unsigned int)needed_len ));
986 return NT_STATUS_INVALID_PARAMETER;
989 /* We must store this blob until complete. */
990 pad = SMB_MALLOC(sizeof(struct pending_auth_data));
991 if (!pad) {
992 return NT_STATUS_NO_MEMORY;
994 pad->needed_len = needed_len - pblob->length;
995 pad->partial_data = data_blob(pblob->data, pblob->length);
996 if (pad->partial_data.data == NULL) {
997 SAFE_FREE(pad);
998 return NT_STATUS_NO_MEMORY;
1000 pad->smbpid = smbpid;
1001 pad->vuid = vuid;
1002 DLIST_ADD(pd_list, pad);
1004 return NT_STATUS_MORE_PROCESSING_REQUIRED;
1007 /****************************************************************************
1008 Reply to a session setup command.
1009 conn POINTER CAN BE NULL HERE !
1010 ****************************************************************************/
1012 static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,
1013 char *outbuf,
1014 int length,int bufsize)
1016 uint8 *p;
1017 DATA_BLOB blob1;
1018 int ret;
1019 size_t bufrem;
1020 fstring native_os, native_lanman, primary_domain;
1021 char *p2;
1022 uint16 data_blob_len = SVAL(inbuf, smb_vwv7);
1023 enum remote_arch_types ra_type = get_remote_arch();
1024 int vuid = SVAL(inbuf,smb_uid);
1025 user_struct *vuser = NULL;
1026 NTSTATUS status = NT_STATUS_OK;
1027 uint16 smbpid = SVAL(inbuf,smb_pid);
1029 DEBUG(3,("Doing spnego session setup\n"));
1031 if (global_client_caps == 0) {
1032 global_client_caps = IVAL(inbuf,smb_vwv10);
1034 if (!(global_client_caps & CAP_STATUS32)) {
1035 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1040 p = (uint8 *)smb_buf(inbuf);
1042 if (data_blob_len == 0) {
1043 /* an invalid request */
1044 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
1047 bufrem = smb_bufrem(inbuf, p);
1048 /* pull the spnego blob */
1049 blob1 = data_blob(p, MIN(bufrem, data_blob_len));
1051 #if 0
1052 file_save("negotiate.dat", blob1.data, blob1.length);
1053 #endif
1055 p2 = inbuf + smb_vwv13 + data_blob_len;
1056 p2 += srvstr_pull_buf(inbuf, native_os, p2, sizeof(native_os), STR_TERMINATE);
1057 p2 += srvstr_pull_buf(inbuf, native_lanman, p2, sizeof(native_lanman), STR_TERMINATE);
1058 p2 += srvstr_pull_buf(inbuf, primary_domain, p2, sizeof(primary_domain), STR_TERMINATE);
1059 DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
1060 native_os, native_lanman, primary_domain));
1062 if ( ra_type == RA_WIN2K ) {
1063 /* Vista sets neither the OS or lanman strings */
1065 if ( !strlen(native_os) && !strlen(native_lanman) )
1066 set_remote_arch(RA_VISTA);
1068 /* Windows 2003 doesn't set the native lanman string,
1069 but does set primary domain which is a bug I think */
1071 if ( !strlen(native_lanman) ) {
1072 ra_lanman_string( primary_domain );
1073 } else {
1074 ra_lanman_string( native_lanman );
1078 vuser = get_partial_auth_user_struct(vuid);
1079 if (!vuser) {
1080 struct pending_auth_data *pad = get_pending_auth_data(smbpid);
1081 if (pad) {
1082 DEBUG(10,("reply_sesssetup_and_X_spnego: found pending vuid %u\n",
1083 (unsigned int)pad->vuid ));
1084 vuid = pad->vuid;
1085 vuser = get_partial_auth_user_struct(vuid);
1089 if (!vuser) {
1090 vuid = register_vuid(NULL, data_blob(NULL, 0), data_blob(NULL, 0), NULL);
1091 if (vuid == UID_FIELD_INVALID ) {
1092 data_blob_free(&blob1);
1093 return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
1096 vuser = get_partial_auth_user_struct(vuid);
1099 if (!vuser) {
1100 data_blob_free(&blob1);
1101 return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
1104 SSVAL(outbuf,smb_uid,vuid);
1106 /* Large (greater than 4k) SPNEGO blobs are split into multiple
1107 * sessionsetup requests as the Windows limit on the security blob
1108 * field is 4k. Bug #4400. JRA.
1111 status = check_spnego_blob_complete(smbpid, vuid, &blob1);
1112 if (!NT_STATUS_IS_OK(status)) {
1113 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1114 /* Real error - kill the intermediate vuid */
1115 invalidate_vuid(vuid);
1117 data_blob_free(&blob1);
1118 return ERROR_NT(nt_status_squash(status));
1121 if (blob1.data[0] == ASN1_APPLICATION(0)) {
1122 /* its a negTokenTarg packet */
1123 ret = reply_spnego_negotiate(conn, inbuf, outbuf, vuid, length, bufsize, blob1,
1124 &vuser->auth_ntlmssp_state);
1125 data_blob_free(&blob1);
1126 return ret;
1129 if (blob1.data[0] == ASN1_CONTEXT(1)) {
1130 /* its a auth packet */
1131 ret = reply_spnego_auth(conn, inbuf, outbuf, vuid, length, bufsize, blob1,
1132 &vuser->auth_ntlmssp_state);
1133 data_blob_free(&blob1);
1134 return ret;
1137 if (strncmp((char *)(blob1.data), "NTLMSSP", 7) == 0) {
1138 DATA_BLOB chal;
1139 if (!vuser->auth_ntlmssp_state) {
1140 status = auth_ntlmssp_start(&vuser->auth_ntlmssp_state);
1141 if (!NT_STATUS_IS_OK(status)) {
1142 /* Kill the intermediate vuid */
1143 invalidate_vuid(vuid);
1144 data_blob_free(&blob1);
1145 return ERROR_NT(nt_status_squash(status));
1149 status = auth_ntlmssp_update(vuser->auth_ntlmssp_state,
1150 blob1, &chal);
1152 data_blob_free(&blob1);
1154 reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid,
1155 &vuser->auth_ntlmssp_state,
1156 &chal, status, False);
1157 data_blob_free(&chal);
1158 return -1;
1161 /* what sort of packet is this? */
1162 DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
1164 data_blob_free(&blob1);
1166 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
1169 /****************************************************************************
1170 On new VC == 0, shutdown *all* old connections and users.
1171 It seems that only NT4.x does this. At W2K and above (XP etc.).
1172 a new session setup with VC==0 is ignored.
1173 ****************************************************************************/
1175 static int shutdown_other_smbds(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf,
1176 void *p)
1178 struct sessionid *sessionid = (struct sessionid *)dbuf.dptr;
1179 const char *ip = (const char *)p;
1181 if (!process_exists(pid_to_procid(sessionid->pid))) {
1182 return 0;
1185 if (sessionid->pid == sys_getpid()) {
1186 return 0;
1189 if (strcmp(ip, sessionid->ip_addr) != 0) {
1190 return 0;
1193 message_send_pid(pid_to_procid(sessionid->pid), MSG_SHUTDOWN,
1194 NULL, 0, True);
1195 return 0;
1198 static void setup_new_vc_session(void)
1200 DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x compatible we would close all old resources.\n"));
1201 #if 0
1202 conn_close_all();
1203 invalidate_all_vuids();
1204 #endif
1205 if (lp_reset_on_zero_vc()) {
1206 session_traverse(shutdown_other_smbds, client_addr());
1210 /****************************************************************************
1211 Reply to a session setup command.
1212 ****************************************************************************/
1214 int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
1215 int length,int bufsize)
1217 int sess_vuid;
1218 int smb_bufsize;
1219 DATA_BLOB lm_resp;
1220 DATA_BLOB nt_resp;
1221 DATA_BLOB plaintext_password;
1222 fstring user;
1223 fstring sub_user; /* Sainitised username for substituion */
1224 fstring domain;
1225 fstring native_os;
1226 fstring native_lanman;
1227 fstring primary_domain;
1228 static BOOL done_sesssetup = False;
1229 auth_usersupplied_info *user_info = NULL;
1230 auth_serversupplied_info *server_info = NULL;
1232 NTSTATUS nt_status;
1234 BOOL doencrypt = global_encrypted_passwords_negotiated;
1236 DATA_BLOB session_key;
1238 START_PROFILE(SMBsesssetupX);
1240 ZERO_STRUCT(lm_resp);
1241 ZERO_STRUCT(nt_resp);
1242 ZERO_STRUCT(plaintext_password);
1244 DEBUG(3,("wct=%d flg2=0x%x\n", CVAL(inbuf, smb_wct), SVAL(inbuf, smb_flg2)));
1246 /* a SPNEGO session setup has 12 command words, whereas a normal
1247 NT1 session setup has 13. See the cifs spec. */
1248 if (CVAL(inbuf, smb_wct) == 12 &&
1249 (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
1250 if (!global_spnego_negotiated) {
1251 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt at SPNEGO session setup when it was not negoitiated.\n"));
1252 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
1255 if (SVAL(inbuf,smb_vwv4) == 0) {
1256 setup_new_vc_session();
1258 return reply_sesssetup_and_X_spnego(conn, inbuf, outbuf, length, bufsize);
1261 smb_bufsize = SVAL(inbuf,smb_vwv2);
1263 if (Protocol < PROTOCOL_NT1) {
1264 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
1266 /* Never do NT status codes with protocols before NT1 as we don't get client caps. */
1267 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1269 if ((passlen1 > MAX_PASS_LEN) || (passlen1 > smb_bufrem(inbuf, smb_buf(inbuf)))) {
1270 return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
1273 if (doencrypt) {
1274 lm_resp = data_blob(smb_buf(inbuf), passlen1);
1275 } else {
1276 plaintext_password = data_blob(smb_buf(inbuf), passlen1+1);
1277 /* Ensure null termination */
1278 plaintext_password.data[passlen1] = 0;
1281 srvstr_pull_buf(inbuf, user, smb_buf(inbuf)+passlen1, sizeof(user), STR_TERMINATE);
1282 *domain = 0;
1284 } else {
1285 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
1286 uint16 passlen2 = SVAL(inbuf,smb_vwv8);
1287 enum remote_arch_types ra_type = get_remote_arch();
1288 char *p = smb_buf(inbuf);
1289 char *save_p = smb_buf(inbuf);
1290 uint16 byte_count;
1293 if(global_client_caps == 0) {
1294 global_client_caps = IVAL(inbuf,smb_vwv11);
1296 if (!(global_client_caps & CAP_STATUS32)) {
1297 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1300 /* client_caps is used as final determination if client is NT or Win95.
1301 This is needed to return the correct error codes in some
1302 circumstances.
1305 if(ra_type == RA_WINNT || ra_type == RA_WIN2K || ra_type == RA_WIN95) {
1306 if(!(global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))) {
1307 set_remote_arch( RA_WIN95);
1312 if (!doencrypt) {
1313 /* both Win95 and WinNT stuff up the password lengths for
1314 non-encrypting systems. Uggh.
1316 if passlen1==24 its a win95 system, and its setting the
1317 password length incorrectly. Luckily it still works with the
1318 default code because Win95 will null terminate the password
1319 anyway
1321 if passlen1>0 and passlen2>0 then maybe its a NT box and its
1322 setting passlen2 to some random value which really stuffs
1323 things up. we need to fix that one. */
1325 if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 && passlen2 != 1)
1326 passlen2 = 0;
1329 /* check for nasty tricks */
1330 if (passlen1 > MAX_PASS_LEN || passlen1 > smb_bufrem(inbuf, p)) {
1331 return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
1334 if (passlen2 > MAX_PASS_LEN || passlen2 > smb_bufrem(inbuf, p+passlen1)) {
1335 return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
1338 /* Save the lanman2 password and the NT md4 password. */
1340 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
1341 doencrypt = False;
1344 if (doencrypt) {
1345 lm_resp = data_blob(p, passlen1);
1346 nt_resp = data_blob(p+passlen1, passlen2);
1347 } else {
1348 pstring pass;
1349 BOOL unic=SVAL(inbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS;
1351 #if 0
1352 /* This was the previous fix. Not sure if it's still valid. JRA. */
1353 if ((ra_type == RA_WINNT) && (passlen2 == 0) && unic && passlen1) {
1354 /* NT4.0 stuffs up plaintext unicode password lengths... */
1355 srvstr_pull(inbuf, pass, smb_buf(inbuf) + 1,
1356 sizeof(pass), passlen1, STR_TERMINATE);
1357 #endif
1359 if (unic && (passlen2 == 0) && passlen1) {
1360 /* Only a ascii plaintext password was sent. */
1361 srvstr_pull(inbuf, pass, smb_buf(inbuf), sizeof(pass),
1362 passlen1, STR_TERMINATE|STR_ASCII);
1363 } else {
1364 srvstr_pull(inbuf, pass, smb_buf(inbuf),
1365 sizeof(pass), unic ? passlen2 : passlen1,
1366 STR_TERMINATE);
1368 plaintext_password = data_blob(pass, strlen(pass)+1);
1371 p += passlen1 + passlen2;
1372 p += srvstr_pull_buf(inbuf, user, p, sizeof(user), STR_TERMINATE);
1373 p += srvstr_pull_buf(inbuf, domain, p, sizeof(domain), STR_TERMINATE);
1374 p += srvstr_pull_buf(inbuf, native_os, p, sizeof(native_os), STR_TERMINATE);
1375 p += srvstr_pull_buf(inbuf, native_lanman, p, sizeof(native_lanman), STR_TERMINATE);
1377 /* not documented or decoded by Ethereal but there is one more string
1378 in the extra bytes which is the same as the PrimaryDomain when using
1379 extended security. Windows NT 4 and 2003 use this string to store
1380 the native lanman string. Windows 9x does not include a string here
1381 at all so we have to check if we have any extra bytes left */
1383 byte_count = SVAL(inbuf, smb_vwv13);
1384 if ( PTR_DIFF(p, save_p) < byte_count)
1385 p += srvstr_pull_buf(inbuf, primary_domain, p, sizeof(primary_domain), STR_TERMINATE);
1386 else
1387 fstrcpy( primary_domain, "null" );
1389 DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
1390 domain, native_os, native_lanman, primary_domain));
1392 if ( ra_type == RA_WIN2K ) {
1393 if ( strlen(native_lanman) == 0 )
1394 ra_lanman_string( primary_domain );
1395 else
1396 ra_lanman_string( native_lanman );
1401 if (SVAL(inbuf,smb_vwv4) == 0) {
1402 setup_new_vc_session();
1405 DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n", domain, user, get_remote_machine_name()));
1407 if (*user) {
1408 if (global_spnego_negotiated) {
1410 /* This has to be here, because this is a perfectly valid behaviour for guest logons :-( */
1412 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt at 'normal' session setup after negotiating spnego.\n"));
1413 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
1415 fstrcpy(sub_user, user);
1416 } else {
1417 fstrcpy(sub_user, lp_guestaccount());
1420 sub_set_smb_name(sub_user);
1422 reload_services(True);
1424 if (lp_security() == SEC_SHARE) {
1425 /* in share level we should ignore any passwords */
1427 data_blob_free(&lm_resp);
1428 data_blob_free(&nt_resp);
1429 data_blob_clear_free(&plaintext_password);
1431 map_username(sub_user);
1432 add_session_user(sub_user);
1433 add_session_workgroup(domain);
1434 /* Then force it to null for the benfit of the code below */
1435 *user = 0;
1438 if (!*user) {
1440 nt_status = check_guest_password(&server_info);
1442 } else if (doencrypt) {
1443 if (!negprot_global_auth_context) {
1444 DEBUG(0, ("reply_sesssetup_and_X: Attempted encrypted session setup without negprot denied!\n"));
1445 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
1447 nt_status = make_user_info_for_reply_enc(&user_info, user, domain,
1448 lm_resp, nt_resp);
1449 if (NT_STATUS_IS_OK(nt_status)) {
1450 nt_status = negprot_global_auth_context->check_ntlm_password(negprot_global_auth_context,
1451 user_info,
1452 &server_info);
1454 } else {
1455 struct auth_context *plaintext_auth_context = NULL;
1456 const uint8 *chal;
1458 nt_status = make_auth_context_subsystem(&plaintext_auth_context);
1460 if (NT_STATUS_IS_OK(nt_status)) {
1461 chal = plaintext_auth_context->get_ntlm_challenge(plaintext_auth_context);
1463 if (!make_user_info_for_reply(&user_info,
1464 user, domain, chal,
1465 plaintext_password)) {
1466 nt_status = NT_STATUS_NO_MEMORY;
1469 if (NT_STATUS_IS_OK(nt_status)) {
1470 nt_status = plaintext_auth_context->check_ntlm_password(plaintext_auth_context,
1471 user_info,
1472 &server_info);
1474 (plaintext_auth_context->free)(&plaintext_auth_context);
1479 free_user_info(&user_info);
1481 if (!NT_STATUS_IS_OK(nt_status)) {
1482 nt_status = do_map_to_guest(nt_status, &server_info, user, domain);
1485 if (!NT_STATUS_IS_OK(nt_status)) {
1486 data_blob_free(&nt_resp);
1487 data_blob_free(&lm_resp);
1488 data_blob_clear_free(&plaintext_password);
1489 return ERROR_NT(nt_status_squash(nt_status));
1492 /* Ensure we can't possible take a code path leading to a null defref. */
1493 if (!server_info) {
1494 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
1497 nt_status = create_local_token(server_info);
1498 if (!NT_STATUS_IS_OK(nt_status)) {
1499 DEBUG(10, ("create_local_token failed: %s\n",
1500 nt_errstr(nt_status)));
1501 data_blob_free(&nt_resp);
1502 data_blob_free(&lm_resp);
1503 data_blob_clear_free(&plaintext_password);
1504 return ERROR_NT(nt_status_squash(nt_status));
1507 if (server_info->user_session_key.data) {
1508 session_key = data_blob(server_info->user_session_key.data, server_info->user_session_key.length);
1509 } else {
1510 session_key = data_blob(NULL, 0);
1513 data_blob_clear_free(&plaintext_password);
1515 /* it's ok - setup a reply */
1516 set_message(outbuf,3,0,True);
1517 if (Protocol >= PROTOCOL_NT1) {
1518 char *p = smb_buf( outbuf );
1519 p += add_signature( outbuf, p );
1520 set_message_end( outbuf, p );
1521 /* perhaps grab OS version here?? */
1524 if (server_info->guest) {
1525 SSVAL(outbuf,smb_vwv2,1);
1528 /* register the name and uid as being validated, so further connections
1529 to a uid can get through without a password, on the same VC */
1531 if (lp_security() == SEC_SHARE) {
1532 sess_vuid = UID_FIELD_INVALID;
1533 data_blob_free(&session_key);
1534 TALLOC_FREE(server_info);
1535 } else {
1536 /* register_vuid keeps the server info */
1537 sess_vuid = register_vuid(server_info, session_key,
1538 nt_resp.data ? nt_resp : lm_resp,
1539 sub_user);
1540 if (sess_vuid == UID_FIELD_INVALID) {
1541 data_blob_free(&nt_resp);
1542 data_blob_free(&lm_resp);
1543 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
1546 /* current_user_info is changed on new vuid */
1547 reload_services( True );
1549 sessionsetup_start_signing_engine(server_info, inbuf);
1552 data_blob_free(&nt_resp);
1553 data_blob_free(&lm_resp);
1555 SSVAL(outbuf,smb_uid,sess_vuid);
1556 SSVAL(inbuf,smb_uid,sess_vuid);
1558 if (!done_sesssetup)
1559 max_send = MIN(max_send,smb_bufsize);
1561 done_sesssetup = True;
1563 END_PROFILE(SMBsesssetupX);
1564 return chain_reply(inbuf,outbuf,length,bufsize);