r14112: * fix checks on return code from register_vuid() which could actually
[Samba.git] / source / smbd / sesssetup.c
blob1abb800627429a596a33a005315b6bfd80b4250b
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 uint32 global_client_caps = 0;
29 on a logon error possibly map the error to success if "map to guest"
30 is set approriately
32 static NTSTATUS do_map_to_guest(NTSTATUS status, auth_serversupplied_info **server_info,
33 const char *user, const char *domain)
35 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
36 if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) ||
37 (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) {
38 DEBUG(3,("No such user %s [%s] - using guest account\n",
39 user, domain));
40 status = make_server_info_guest(server_info);
44 if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
45 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) {
46 DEBUG(3,("Registered username %s for guest access\n",user));
47 status = make_server_info_guest(server_info);
51 return status;
54 /****************************************************************************
55 Add the standard 'Samba' signature to the end of the session setup.
56 ****************************************************************************/
58 static int add_signature(char *outbuf, char *p)
60 char *start = p;
61 fstring lanman;
63 fstr_sprintf( lanman, "Samba %s", SAMBA_VERSION_STRING);
65 p += srvstr_push(outbuf, p, "Unix", -1, STR_TERMINATE);
66 p += srvstr_push(outbuf, p, lanman, -1, STR_TERMINATE);
67 p += srvstr_push(outbuf, p, lp_workgroup(), -1, STR_TERMINATE);
69 return PTR_DIFF(p, start);
72 /****************************************************************************
73 Start the signing engine if needed. Don't fail signing here.
74 ****************************************************************************/
76 static void sessionsetup_start_signing_engine(const auth_serversupplied_info *server_info, char *inbuf)
78 if (!server_info->guest && !srv_signing_started()) {
79 /* We need to start the signing engine
80 * here but a W2K client sends the old
81 * "BSRSPYL " signature instead of the
82 * correct one. Subsequent packets will
83 * be correct.
85 srv_check_sign_mac(inbuf, False);
89 /****************************************************************************
90 Send a security blob via a session setup reply.
91 ****************************************************************************/
93 static BOOL reply_sesssetup_blob(connection_struct *conn, char *outbuf,
94 DATA_BLOB blob, NTSTATUS nt_status)
96 char *p;
98 set_message(outbuf,4,0,True);
100 nt_status = nt_status_squash(nt_status);
101 SIVAL(outbuf, smb_rcls, NT_STATUS_V(nt_status));
102 SSVAL(outbuf, smb_vwv0, 0xFF); /* no chaining possible */
103 SSVAL(outbuf, smb_vwv3, blob.length);
104 p = smb_buf(outbuf);
106 /* should we cap this? */
107 memcpy(p, blob.data, blob.length);
108 p += blob.length;
110 p += add_signature( outbuf, p );
112 set_message_end(outbuf,p);
114 show_msg(outbuf);
115 return send_smb(smbd_server_fd(),outbuf);
118 /****************************************************************************
119 Do a 'guest' logon, getting back the
120 ****************************************************************************/
122 static NTSTATUS check_guest_password(auth_serversupplied_info **server_info)
124 struct auth_context *auth_context;
125 auth_usersupplied_info *user_info = NULL;
127 NTSTATUS nt_status;
128 unsigned char chal[8];
130 ZERO_STRUCT(chal);
132 DEBUG(3,("Got anonymous request\n"));
134 if (!NT_STATUS_IS_OK(nt_status = make_auth_context_fixed(&auth_context, chal))) {
135 return nt_status;
138 if (!make_user_info_guest(&user_info)) {
139 (auth_context->free)(&auth_context);
140 return NT_STATUS_NO_MEMORY;
143 nt_status = auth_context->check_ntlm_password(auth_context, user_info, server_info);
144 (auth_context->free)(&auth_context);
145 free_user_info(&user_info);
146 return nt_status;
150 #ifdef HAVE_KRB5
151 /****************************************************************************
152 reply to a session setup spnego negotiate packet for kerberos
153 ****************************************************************************/
154 static int reply_spnego_kerberos(connection_struct *conn,
155 char *inbuf, char *outbuf,
156 int length, int bufsize,
157 DATA_BLOB *secblob)
159 TALLOC_CTX *mem_ctx;
160 DATA_BLOB ticket;
161 char *client, *p, *domain;
162 fstring netbios_domain_name;
163 struct passwd *pw;
164 fstring user;
165 int sess_vuid;
166 NTSTATUS ret;
167 PAC_DATA *pac_data;
168 DATA_BLOB ap_rep, ap_rep_wrapped, response;
169 auth_serversupplied_info *server_info = NULL;
170 DATA_BLOB session_key = data_blob(NULL, 0);
171 uint8 tok_id[2];
172 DATA_BLOB nullblob = data_blob(NULL, 0);
173 fstring real_username;
174 BOOL map_domainuser_to_guest = False;
175 PAC_LOGON_INFO *logon_info = NULL;
177 ZERO_STRUCT(ticket);
178 ZERO_STRUCT(pac_data);
179 ZERO_STRUCT(ap_rep);
180 ZERO_STRUCT(ap_rep_wrapped);
181 ZERO_STRUCT(response);
183 mem_ctx = talloc_init("reply_spnego_kerberos");
184 if (mem_ctx == NULL)
185 return ERROR_NT(NT_STATUS_NO_MEMORY);
187 if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) {
188 talloc_destroy(mem_ctx);
189 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
192 ret = ads_verify_ticket(mem_ctx, lp_realm(), &ticket, &client, &pac_data, &ap_rep, &session_key);
194 data_blob_free(&ticket);
196 if (!NT_STATUS_IS_OK(ret)) {
197 DEBUG(1,("Failed to verify incoming ticket!\n"));
198 talloc_destroy(mem_ctx);
199 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
202 DEBUG(3,("Ticket name is [%s]\n", client));
204 p = strchr_m(client, '@');
205 if (!p) {
206 DEBUG(3,("Doesn't look like a valid principal\n"));
207 data_blob_free(&ap_rep);
208 data_blob_free(&session_key);
209 SAFE_FREE(client);
210 talloc_destroy(mem_ctx);
211 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
214 *p = 0;
216 /* save the PAC data if we have it */
218 if (pac_data) {
219 logon_info = get_logon_info_from_pac(pac_data);
220 netsamlogon_cache_store( client, &logon_info->info3 );
223 if (!strequal(p+1, lp_realm())) {
224 DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1));
225 if (!lp_allow_trusted_domains()) {
226 data_blob_free(&ap_rep);
227 data_blob_free(&session_key);
228 SAFE_FREE(client);
229 talloc_destroy(mem_ctx);
230 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
234 /* this gives a fully qualified user name (ie. with full realm).
235 that leads to very long usernames, but what else can we do? */
237 domain = p+1;
239 if (logon_info && logon_info->info3.hdr_logon_dom.uni_str_len) {
241 unistr2_to_ascii(netbios_domain_name, &logon_info->info3.uni_logon_dom, -1);
242 domain = netbios_domain_name;
243 DEBUG(10, ("Mapped to [%s] (using PAC)\n", domain));
245 } else {
247 /* If we have winbind running, we can (and must) shorten the
248 username by using the short netbios name. Otherwise we will
249 have inconsistent user names. With Kerberos, we get the
250 fully qualified realm, with ntlmssp we get the short
251 name. And even w2k3 does use ntlmssp if you for example
252 connect to an ip address. */
254 struct winbindd_request wb_request;
255 struct winbindd_response wb_response;
256 NSS_STATUS wb_result;
258 ZERO_STRUCT(wb_request);
259 ZERO_STRUCT(wb_response);
261 DEBUG(10, ("Mapping [%s] to short name\n", domain));
263 fstrcpy(wb_request.domain_name, domain);
265 wb_result = winbindd_request_response(WINBINDD_DOMAIN_INFO,
266 &wb_request, &wb_response);
268 if (wb_result == NSS_STATUS_SUCCESS) {
270 fstrcpy(netbios_domain_name,
271 wb_response.data.domain_info.name);
272 domain = netbios_domain_name;
274 DEBUG(10, ("Mapped to [%s] (using Winbind)\n", domain));
275 } else {
276 DEBUG(3, ("Could not find short name -- winbind "
277 "not running?\n"));
281 fstr_sprintf(user, "%s%c%s", domain, *lp_winbind_separator(), client);
283 /* lookup the passwd struct, create a new user if necessary */
285 map_username( user );
287 pw = smb_getpwnam( mem_ctx, user, real_username, True );
288 if (!pw) {
290 /* this was originally the behavior of Samba 2.2, if a user
291 did not have a local uid but has been authenticated, then
292 map them to a guest account */
294 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID){
295 map_domainuser_to_guest = True;
296 fstrcpy(user,lp_guestaccount());
297 pw = smb_getpwnam( mem_ctx, user, real_username, True );
300 /* extra sanity check that the guest account is valid */
302 if ( !pw ) {
303 DEBUG(1,("Username %s is invalid on this system\n", user));
304 SAFE_FREE(client);
305 data_blob_free(&ap_rep);
306 data_blob_free(&session_key);
307 talloc_destroy(mem_ctx);
308 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
312 /* setup the string used by %U */
314 sub_set_smb_name( real_username );
315 reload_services(True);
316 if ( map_domainuser_to_guest ) {
317 make_server_info_guest(&server_info);
318 } else if (logon_info) {
319 ret = make_server_info_pac(&server_info, real_username, pw, logon_info);
321 if ( !NT_STATUS_IS_OK(ret) ) {
322 DEBUG(1,("make_server_info_pac failed: %s!\n",
323 nt_errstr(ret)));
324 SAFE_FREE(client);
325 data_blob_free(&ap_rep);
326 data_blob_free(&session_key);
327 talloc_destroy(mem_ctx);
328 return ERROR_NT(ret);
331 } else {
332 ret = make_server_info_pw(&server_info, real_username, pw);
334 if ( !NT_STATUS_IS_OK(ret) ) {
335 DEBUG(1,("make_server_info_pw failed: %s!\n",
336 nt_errstr(ret)));
337 SAFE_FREE(client);
338 data_blob_free(&ap_rep);
339 data_blob_free(&session_key);
340 talloc_destroy(mem_ctx);
341 return ERROR_NT(ret);
344 /* make_server_info_pw does not set the domain. Without this
345 * we end up with the local netbios name in substitutions for
346 * %D. */
348 if (server_info->sam_account != NULL) {
349 pdb_set_domain(server_info->sam_account, domain, PDB_SET);
353 /* we need to build the token for the user. make_server_info_guest()
354 already does this */
356 if ( !server_info->ptok ) {
357 ret = create_local_token( server_info );
358 if ( !NT_STATUS_IS_OK(ret) ) {
359 SAFE_FREE(client);
360 data_blob_free(&ap_rep);
361 data_blob_free(&session_key);
362 TALLOC_FREE( mem_ctx );
363 TALLOC_FREE( server_info );
364 return ERROR_NT(ret);
368 /* register_vuid keeps the server info */
369 /* register_vuid takes ownership of session_key, no need to free after this.
370 A better interface would copy it.... */
371 sess_vuid = register_vuid(server_info, session_key, nullblob, client);
373 SAFE_FREE(client);
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( True );
381 set_message(outbuf,4,0,True);
382 SSVAL(outbuf, smb_vwv3, 0);
384 if (server_info->guest) {
385 SSVAL(outbuf,smb_vwv2,1);
388 SSVAL(outbuf, smb_uid, sess_vuid);
390 sessionsetup_start_signing_engine(server_info, inbuf);
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(ap_rep, TOK_ID_KRB_AP_REP);
396 } else {
397 ap_rep_wrapped = data_blob(NULL, 0);
399 response = spnego_gen_auth_response(&ap_rep_wrapped, ret, OID_KERBEROS5_OLD);
400 reply_sesssetup_blob(conn, outbuf, response, ret);
402 data_blob_free(&ap_rep);
403 data_blob_free(&ap_rep_wrapped);
404 data_blob_free(&response);
405 talloc_destroy(mem_ctx);
407 return -1; /* already replied */
409 #endif
411 /****************************************************************************
412 Send a session setup reply, wrapped in SPNEGO.
413 Get vuid and check first.
414 End the NTLMSSP exchange context if we are OK/complete fail
415 This should be split into two functions, one to handle each
416 leg of the NTLM auth steps.
417 ***************************************************************************/
419 static BOOL reply_spnego_ntlmssp(connection_struct *conn, char *inbuf, char *outbuf,
420 uint16 vuid,
421 AUTH_NTLMSSP_STATE **auth_ntlmssp_state,
422 DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status,
423 BOOL wrap)
425 BOOL ret;
426 DATA_BLOB response;
427 struct auth_serversupplied_info *server_info = NULL;
429 if (NT_STATUS_IS_OK(nt_status)) {
430 server_info = (*auth_ntlmssp_state)->server_info;
431 } else {
432 nt_status = do_map_to_guest(nt_status,
433 &server_info,
434 (*auth_ntlmssp_state)->ntlmssp_state->user,
435 (*auth_ntlmssp_state)->ntlmssp_state->domain);
438 if (NT_STATUS_IS_OK(nt_status)) {
439 int sess_vuid;
440 DATA_BLOB nullblob = data_blob(NULL, 0);
441 DATA_BLOB session_key = data_blob((*auth_ntlmssp_state)->ntlmssp_state->session_key.data, (*auth_ntlmssp_state)->ntlmssp_state->session_key.length);
443 /* register_vuid keeps the server info */
444 sess_vuid = register_vuid(server_info, session_key, nullblob, (*auth_ntlmssp_state)->ntlmssp_state->user);
445 (*auth_ntlmssp_state)->server_info = NULL;
447 if (sess_vuid == UID_FIELD_INVALID ) {
448 nt_status = NT_STATUS_LOGON_FAILURE;
449 } else {
451 /* current_user_info is changed on new vuid */
452 reload_services( True );
454 set_message(outbuf,4,0,True);
455 SSVAL(outbuf, smb_vwv3, 0);
457 if (server_info->guest) {
458 SSVAL(outbuf,smb_vwv2,1);
461 SSVAL(outbuf,smb_uid,sess_vuid);
463 sessionsetup_start_signing_engine(server_info, inbuf);
467 if (wrap) {
468 response = spnego_gen_auth_response(ntlmssp_blob, nt_status, OID_NTLMSSP);
469 } else {
470 response = *ntlmssp_blob;
473 ret = reply_sesssetup_blob(conn, outbuf, response, nt_status);
474 if (wrap) {
475 data_blob_free(&response);
478 /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
479 and the other end, that we are not finished yet. */
481 if (!ret || !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
482 /* NB. This is *NOT* an error case. JRA */
483 auth_ntlmssp_end(auth_ntlmssp_state);
484 /* Kill the intermediate vuid */
485 invalidate_vuid(vuid);
488 return ret;
491 /****************************************************************************
492 Reply to a session setup spnego negotiate packet.
493 ****************************************************************************/
495 static int reply_spnego_negotiate(connection_struct *conn,
496 char *inbuf,
497 char *outbuf,
498 uint16 vuid,
499 int length, int bufsize,
500 DATA_BLOB blob1,
501 AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
503 char *OIDs[ASN1_MAX_OIDS];
504 DATA_BLOB secblob;
505 int i;
506 DATA_BLOB chal;
507 #ifdef HAVE_KRB5
508 BOOL got_kerberos_mechanism = False;
509 #endif
510 NTSTATUS nt_status;
512 /* parse out the OIDs and the first sec blob */
513 if (!parse_negTokenTarg(blob1, OIDs, &secblob)) {
514 /* Kill the intermediate vuid */
515 invalidate_vuid(vuid);
517 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
520 /* only look at the first OID for determining the mechToken --
521 accoirding to RFC2478, we should choose the one we want
522 and renegotiate, but i smell a client bug here..
524 Problem observed when connecting to a member (samba box)
525 of an AD domain as a user in a Samba domain. Samba member
526 server sent back krb5/mskrb5/ntlmssp as mechtypes, but the
527 client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an
528 NTLMSSP mechtoken. --jerry */
530 #ifdef HAVE_KRB5
531 if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||
532 strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
533 got_kerberos_mechanism = True;
535 #endif
537 for (i=0;OIDs[i];i++) {
538 DEBUG(3,("Got OID %s\n", OIDs[i]));
539 free(OIDs[i]);
541 DEBUG(3,("Got secblob of size %lu\n", (unsigned long)secblob.length));
543 #ifdef HAVE_KRB5
544 if ( got_kerberos_mechanism && ((lp_security()==SEC_ADS) || lp_use_kerberos_keytab()) ) {
545 int ret = reply_spnego_kerberos(conn, inbuf, outbuf,
546 length, bufsize, &secblob);
547 data_blob_free(&secblob);
548 /* Kill the intermediate vuid */
549 invalidate_vuid(vuid);
551 return ret;
553 #endif
555 if (*auth_ntlmssp_state) {
556 auth_ntlmssp_end(auth_ntlmssp_state);
559 nt_status = auth_ntlmssp_start(auth_ntlmssp_state);
560 if (!NT_STATUS_IS_OK(nt_status)) {
561 /* Kill the intermediate vuid */
562 invalidate_vuid(vuid);
564 return ERROR_NT(nt_status);
567 nt_status = auth_ntlmssp_update(*auth_ntlmssp_state,
568 secblob, &chal);
570 data_blob_free(&secblob);
572 reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid, auth_ntlmssp_state,
573 &chal, nt_status, True);
575 data_blob_free(&chal);
577 /* already replied */
578 return -1;
581 /****************************************************************************
582 Reply to a session setup spnego auth packet.
583 ****************************************************************************/
585 static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
586 uint16 vuid,
587 int length, int bufsize,
588 DATA_BLOB blob1,
589 AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
591 DATA_BLOB auth, auth_reply;
592 NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
594 if (!spnego_parse_auth(blob1, &auth)) {
595 #if 0
596 file_save("auth.dat", blob1.data, blob1.length);
597 #endif
598 /* Kill the intermediate vuid */
599 invalidate_vuid(vuid);
601 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
604 if (!*auth_ntlmssp_state) {
605 /* Kill the intermediate vuid */
606 invalidate_vuid(vuid);
608 /* auth before negotiatiate? */
609 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
612 nt_status = auth_ntlmssp_update(*auth_ntlmssp_state,
613 auth, &auth_reply);
615 data_blob_free(&auth);
617 reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid,
618 auth_ntlmssp_state,
619 &auth_reply, nt_status, True);
621 data_blob_free(&auth_reply);
623 /* and tell smbd that we have already replied to this packet */
624 return -1;
627 /****************************************************************************
628 Reply to a session setup command.
629 ****************************************************************************/
631 static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,
632 char *outbuf,
633 int length,int bufsize)
635 uint8 *p;
636 DATA_BLOB blob1;
637 int ret;
638 size_t bufrem;
639 fstring native_os, native_lanman, primary_domain;
640 char *p2;
641 uint16 data_blob_len = SVAL(inbuf, smb_vwv7);
642 enum remote_arch_types ra_type = get_remote_arch();
643 int vuid = SVAL(inbuf,smb_uid);
644 user_struct *vuser = NULL;
646 DEBUG(3,("Doing spnego session setup\n"));
648 if (global_client_caps == 0) {
649 global_client_caps = IVAL(inbuf,smb_vwv10);
651 if (!(global_client_caps & CAP_STATUS32)) {
652 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
657 p = (uint8 *)smb_buf(inbuf);
659 if (data_blob_len == 0) {
660 /* an invalid request */
661 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
664 bufrem = smb_bufrem(inbuf, p);
665 /* pull the spnego blob */
666 blob1 = data_blob(p, MIN(bufrem, data_blob_len));
668 #if 0
669 file_save("negotiate.dat", blob1.data, blob1.length);
670 #endif
672 p2 = inbuf + smb_vwv13 + data_blob_len;
673 p2 += srvstr_pull_buf(inbuf, native_os, p2, sizeof(native_os), STR_TERMINATE);
674 p2 += srvstr_pull_buf(inbuf, native_lanman, p2, sizeof(native_lanman), STR_TERMINATE);
675 p2 += srvstr_pull_buf(inbuf, primary_domain, p2, sizeof(primary_domain), STR_TERMINATE);
676 DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
677 native_os, native_lanman, primary_domain));
679 if ( ra_type == RA_WIN2K ) {
680 /* Windows 2003 doesn't set the native lanman string,
681 but does set primary domain which is a bug I think */
683 if ( !strlen(native_lanman) )
684 ra_lanman_string( primary_domain );
685 else
686 ra_lanman_string( native_lanman );
689 vuser = get_partial_auth_user_struct(vuid);
690 if (!vuser) {
691 vuid = register_vuid(NULL, data_blob(NULL, 0), data_blob(NULL, 0), NULL);
692 if (vuid == UID_FIELD_INVALID ) {
693 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
696 vuser = get_partial_auth_user_struct(vuid);
699 if (!vuser) {
700 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
703 SSVAL(outbuf,smb_uid,vuid);
705 if (blob1.data[0] == ASN1_APPLICATION(0)) {
706 /* its a negTokenTarg packet */
707 ret = reply_spnego_negotiate(conn, inbuf, outbuf, vuid, length, bufsize, blob1,
708 &vuser->auth_ntlmssp_state);
709 data_blob_free(&blob1);
710 return ret;
713 if (blob1.data[0] == ASN1_CONTEXT(1)) {
714 /* its a auth packet */
715 ret = reply_spnego_auth(conn, inbuf, outbuf, vuid, length, bufsize, blob1,
716 &vuser->auth_ntlmssp_state);
717 data_blob_free(&blob1);
718 return ret;
721 if (strncmp((char *)(blob1.data), "NTLMSSP", 7) == 0) {
722 DATA_BLOB chal;
723 NTSTATUS nt_status;
724 if (!vuser->auth_ntlmssp_state) {
725 nt_status = auth_ntlmssp_start(&vuser->auth_ntlmssp_state);
726 if (!NT_STATUS_IS_OK(nt_status)) {
727 /* Kill the intermediate vuid */
728 invalidate_vuid(vuid);
730 return ERROR_NT(nt_status);
734 nt_status = auth_ntlmssp_update(vuser->auth_ntlmssp_state,
735 blob1, &chal);
737 data_blob_free(&blob1);
739 reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid,
740 &vuser->auth_ntlmssp_state,
741 &chal, nt_status, False);
742 data_blob_free(&chal);
743 return -1;
746 /* what sort of packet is this? */
747 DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
749 data_blob_free(&blob1);
751 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
754 /****************************************************************************
755 On new VC == 0, shutdown *all* old connections and users.
756 It seems that only NT4.x does this. At W2K and above (XP etc.).
757 a new session setup with VC==0 is ignored.
758 ****************************************************************************/
760 static int shutdown_other_smbds(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf,
761 void *p)
763 struct sessionid *sessionid = (struct sessionid *)dbuf.dptr;
764 const char *ip = (const char *)p;
766 if (!process_exists(pid_to_procid(sessionid->pid))) {
767 return 0;
770 if (sessionid->pid == sys_getpid()) {
771 return 0;
774 if (strcmp(ip, sessionid->ip_addr) != 0) {
775 return 0;
778 message_send_pid(pid_to_procid(sessionid->pid), MSG_SHUTDOWN,
779 NULL, 0, True);
780 return 0;
783 static void setup_new_vc_session(void)
785 DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x compatible we would close all old resources.\n"));
786 #if 0
787 conn_close_all();
788 invalidate_all_vuids();
789 #endif
790 if (lp_reset_on_zero_vc()) {
791 session_traverse(shutdown_other_smbds, client_addr());
795 /****************************************************************************
796 Reply to a session setup command.
797 ****************************************************************************/
799 int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
800 int length,int bufsize)
802 int sess_vuid;
803 int smb_bufsize;
804 DATA_BLOB lm_resp;
805 DATA_BLOB nt_resp;
806 DATA_BLOB plaintext_password;
807 fstring user;
808 fstring sub_user; /* Sainitised username for substituion */
809 fstring domain;
810 fstring native_os;
811 fstring native_lanman;
812 fstring primary_domain;
813 static BOOL done_sesssetup = False;
814 extern BOOL global_encrypted_passwords_negotiated;
815 extern BOOL global_spnego_negotiated;
816 extern enum protocol_types Protocol;
817 extern int max_send;
819 auth_usersupplied_info *user_info = NULL;
820 extern struct auth_context *negprot_global_auth_context;
821 auth_serversupplied_info *server_info = NULL;
823 NTSTATUS nt_status;
825 BOOL doencrypt = global_encrypted_passwords_negotiated;
827 DATA_BLOB session_key;
829 START_PROFILE(SMBsesssetupX);
831 ZERO_STRUCT(lm_resp);
832 ZERO_STRUCT(nt_resp);
833 ZERO_STRUCT(plaintext_password);
835 DEBUG(3,("wct=%d flg2=0x%x\n", CVAL(inbuf, smb_wct), SVAL(inbuf, smb_flg2)));
837 /* a SPNEGO session setup has 12 command words, whereas a normal
838 NT1 session setup has 13. See the cifs spec. */
839 if (CVAL(inbuf, smb_wct) == 12 &&
840 (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
841 if (!global_spnego_negotiated) {
842 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt at SPNEGO session setup when it was not negoitiated.\n"));
843 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
846 if (SVAL(inbuf,smb_vwv4) == 0) {
847 setup_new_vc_session();
849 return reply_sesssetup_and_X_spnego(conn, inbuf, outbuf, length, bufsize);
852 smb_bufsize = SVAL(inbuf,smb_vwv2);
854 if (Protocol < PROTOCOL_NT1) {
855 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
857 /* Never do NT status codes with protocols before NT1 as we don't get client caps. */
858 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
860 if ((passlen1 > MAX_PASS_LEN) || (passlen1 > smb_bufrem(inbuf, smb_buf(inbuf)))) {
861 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
864 if (doencrypt) {
865 lm_resp = data_blob(smb_buf(inbuf), passlen1);
866 } else {
867 plaintext_password = data_blob(smb_buf(inbuf), passlen1+1);
868 /* Ensure null termination */
869 plaintext_password.data[passlen1] = 0;
872 srvstr_pull_buf(inbuf, user, smb_buf(inbuf)+passlen1, sizeof(user), STR_TERMINATE);
873 *domain = 0;
875 } else {
876 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
877 uint16 passlen2 = SVAL(inbuf,smb_vwv8);
878 enum remote_arch_types ra_type = get_remote_arch();
879 char *p = smb_buf(inbuf);
880 char *save_p = smb_buf(inbuf);
881 uint16 byte_count;
884 if(global_client_caps == 0) {
885 global_client_caps = IVAL(inbuf,smb_vwv11);
887 if (!(global_client_caps & CAP_STATUS32)) {
888 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
891 /* client_caps is used as final determination if client is NT or Win95.
892 This is needed to return the correct error codes in some
893 circumstances.
896 if(ra_type == RA_WINNT || ra_type == RA_WIN2K || ra_type == RA_WIN95) {
897 if(!(global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))) {
898 set_remote_arch( RA_WIN95);
903 if (!doencrypt) {
904 /* both Win95 and WinNT stuff up the password lengths for
905 non-encrypting systems. Uggh.
907 if passlen1==24 its a win95 system, and its setting the
908 password length incorrectly. Luckily it still works with the
909 default code because Win95 will null terminate the password
910 anyway
912 if passlen1>0 and passlen2>0 then maybe its a NT box and its
913 setting passlen2 to some random value which really stuffs
914 things up. we need to fix that one. */
916 if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 && passlen2 != 1)
917 passlen2 = 0;
920 /* check for nasty tricks */
921 if (passlen1 > MAX_PASS_LEN || passlen1 > smb_bufrem(inbuf, p)) {
922 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
925 if (passlen2 > MAX_PASS_LEN || passlen2 > smb_bufrem(inbuf, p+passlen1)) {
926 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
929 /* Save the lanman2 password and the NT md4 password. */
931 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
932 doencrypt = False;
935 if (doencrypt) {
936 lm_resp = data_blob(p, passlen1);
937 nt_resp = data_blob(p+passlen1, passlen2);
938 } else {
939 pstring pass;
940 BOOL unic=SVAL(inbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS;
942 #if 0
943 /* This was the previous fix. Not sure if it's still valid. JRA. */
944 if ((ra_type == RA_WINNT) && (passlen2 == 0) && unic && passlen1) {
945 /* NT4.0 stuffs up plaintext unicode password lengths... */
946 srvstr_pull(inbuf, pass, smb_buf(inbuf) + 1,
947 sizeof(pass), passlen1, STR_TERMINATE);
948 #endif
950 if (unic && (passlen2 == 0) && passlen1) {
951 /* Only a ascii plaintext password was sent. */
952 srvstr_pull(inbuf, pass, smb_buf(inbuf), sizeof(pass),
953 passlen1, STR_TERMINATE|STR_ASCII);
954 } else {
955 srvstr_pull(inbuf, pass, smb_buf(inbuf),
956 sizeof(pass), unic ? passlen2 : passlen1,
957 STR_TERMINATE);
959 plaintext_password = data_blob(pass, strlen(pass)+1);
962 p += passlen1 + passlen2;
963 p += srvstr_pull_buf(inbuf, user, p, sizeof(user), STR_TERMINATE);
964 p += srvstr_pull_buf(inbuf, domain, p, sizeof(domain), STR_TERMINATE);
965 p += srvstr_pull_buf(inbuf, native_os, p, sizeof(native_os), STR_TERMINATE);
966 p += srvstr_pull_buf(inbuf, native_lanman, p, sizeof(native_lanman), STR_TERMINATE);
968 /* not documented or decoded by Ethereal but there is one more string
969 in the extra bytes which is the same as the PrimaryDomain when using
970 extended security. Windows NT 4 and 2003 use this string to store
971 the native lanman string. Windows 9x does not include a string here
972 at all so we have to check if we have any extra bytes left */
974 byte_count = SVAL(inbuf, smb_vwv13);
975 if ( PTR_DIFF(p, save_p) < byte_count)
976 p += srvstr_pull_buf(inbuf, primary_domain, p, sizeof(primary_domain), STR_TERMINATE);
977 else
978 fstrcpy( primary_domain, "null" );
980 DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
981 domain, native_os, native_lanman, primary_domain));
983 if ( ra_type == RA_WIN2K ) {
984 if ( strlen(native_lanman) == 0 )
985 ra_lanman_string( primary_domain );
986 else
987 ra_lanman_string( native_lanman );
992 if (SVAL(inbuf,smb_vwv4) == 0) {
993 setup_new_vc_session();
996 DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n", domain, user, get_remote_machine_name()));
998 if (*user) {
999 if (global_spnego_negotiated) {
1001 /* This has to be here, because this is a perfectly valid behaviour for guest logons :-( */
1003 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt at 'normal' session setup after negotiating spnego.\n"));
1004 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
1006 fstrcpy(sub_user, user);
1007 } else {
1008 fstrcpy(sub_user, lp_guestaccount());
1011 sub_set_smb_name(sub_user);
1013 reload_services(True);
1015 if (lp_security() == SEC_SHARE) {
1016 /* in share level we should ignore any passwords */
1018 data_blob_free(&lm_resp);
1019 data_blob_free(&nt_resp);
1020 data_blob_clear_free(&plaintext_password);
1022 map_username(sub_user);
1023 add_session_user(sub_user);
1024 /* Then force it to null for the benfit of the code below */
1025 *user = 0;
1028 if (!*user) {
1030 nt_status = check_guest_password(&server_info);
1032 } else if (doencrypt) {
1033 if (!negprot_global_auth_context) {
1034 DEBUG(0, ("reply_sesssetup_and_X: Attempted encrypted session setup without negprot denied!\n"));
1035 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
1037 nt_status = make_user_info_for_reply_enc(&user_info, user, domain,
1038 lm_resp, nt_resp);
1039 if (NT_STATUS_IS_OK(nt_status)) {
1040 nt_status = negprot_global_auth_context->check_ntlm_password(negprot_global_auth_context,
1041 user_info,
1042 &server_info);
1044 } else {
1045 struct auth_context *plaintext_auth_context = NULL;
1046 const uint8 *chal;
1047 if (NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&plaintext_auth_context))) {
1048 chal = plaintext_auth_context->get_ntlm_challenge(plaintext_auth_context);
1050 if (!make_user_info_for_reply(&user_info,
1051 user, domain, chal,
1052 plaintext_password)) {
1053 nt_status = NT_STATUS_NO_MEMORY;
1056 if (NT_STATUS_IS_OK(nt_status)) {
1057 nt_status = plaintext_auth_context->check_ntlm_password(plaintext_auth_context,
1058 user_info,
1059 &server_info);
1061 (plaintext_auth_context->free)(&plaintext_auth_context);
1066 free_user_info(&user_info);
1068 if (!NT_STATUS_IS_OK(nt_status)) {
1069 nt_status = do_map_to_guest(nt_status, &server_info, user, domain);
1072 if (!NT_STATUS_IS_OK(nt_status)) {
1073 data_blob_free(&nt_resp);
1074 data_blob_free(&lm_resp);
1075 data_blob_clear_free(&plaintext_password);
1076 return ERROR_NT(nt_status_squash(nt_status));
1079 nt_status = create_local_token(server_info);
1080 if (!NT_STATUS_IS_OK(nt_status)) {
1081 DEBUG(10, ("create_local_token failed: %s\n",
1082 nt_errstr(nt_status)));
1083 data_blob_free(&nt_resp);
1084 data_blob_free(&lm_resp);
1085 data_blob_clear_free(&plaintext_password);
1086 return ERROR_NT(nt_status_squash(nt_status));
1089 if (server_info->user_session_key.data) {
1090 session_key = data_blob(server_info->user_session_key.data, server_info->user_session_key.length);
1091 } else {
1092 session_key = data_blob(NULL, 0);
1095 data_blob_clear_free(&plaintext_password);
1097 /* it's ok - setup a reply */
1098 set_message(outbuf,3,0,True);
1099 if (Protocol >= PROTOCOL_NT1) {
1100 char *p = smb_buf( outbuf );
1101 p += add_signature( outbuf, p );
1102 set_message_end( outbuf, p );
1103 /* perhaps grab OS version here?? */
1106 if (server_info->guest) {
1107 SSVAL(outbuf,smb_vwv2,1);
1110 /* register the name and uid as being validated, so further connections
1111 to a uid can get through without a password, on the same VC */
1113 /* register_vuid keeps the server info */
1114 sess_vuid = register_vuid(server_info, session_key, nt_resp.data ? nt_resp : lm_resp, sub_user);
1115 data_blob_free(&nt_resp);
1116 data_blob_free(&lm_resp);
1118 if (sess_vuid == UID_FIELD_INVALID) {
1119 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
1122 /* current_user_info is changed on new vuid */
1123 reload_services( True );
1125 sessionsetup_start_signing_engine(server_info, inbuf);
1127 SSVAL(outbuf,smb_uid,sess_vuid);
1128 SSVAL(inbuf,smb_uid,sess_vuid);
1130 if (!done_sesssetup)
1131 max_send = MIN(max_send,smb_bufsize);
1133 done_sesssetup = True;
1135 END_PROFILE(SMBsesssetupX);
1136 return chain_reply(inbuf,outbuf,length,bufsize);