sesssetup.c

来自「samba-3.0.22.tar.gz 编译smb服务器的源码」· C语言 代码 · 共 1,115 行 · 第 1/3 页

C
1,115
字号
/*    Unix SMB/CIFS implementation.   handle SMBsessionsetup   Copyright (C) Andrew Tridgell 1998-2001   Copyright (C) Andrew Bartlett      2001   Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002   Copyright (C) Luke Howard          2003   This program is free software; you can redistribute it and/or modify   it under the terms of the GNU General Public License as published by   the Free Software Foundation; either version 2 of the License, or   (at your option) any later version.      This program is distributed in the hope that it will be useful,   but WITHOUT ANY WARRANTY; without even the implied warranty of   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   GNU General Public License for more details.      You should have received a copy of the GNU General Public License   along with this program; if not, write to the Free Software   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*/#include "includes.h"uint32 global_client_caps = 0;/*  on a logon error possibly map the error to success if "map to guest"  is set approriately*/static NTSTATUS do_map_to_guest(NTSTATUS status, auth_serversupplied_info **server_info,				const char *user, const char *domain){	if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {		if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) || 		    (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) {			DEBUG(3,("No such user %s [%s] - using guest account\n",				 user, domain));			status = make_server_info_guest(server_info);		}	}	if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {		if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) {			DEBUG(3,("Registered username %s for guest access\n",user));			status = make_server_info_guest(server_info);		}	}	return status;}/**************************************************************************** Add the standard 'Samba' signature to the end of the session setup.****************************************************************************/static int add_signature(char *outbuf, char *p){	char *start = p;	fstring lanman;	fstr_sprintf( lanman, "Samba %s", SAMBA_VERSION_STRING);	p += srvstr_push(outbuf, p, "Unix", -1, STR_TERMINATE);	p += srvstr_push(outbuf, p, lanman, -1, STR_TERMINATE);	p += srvstr_push(outbuf, p, lp_workgroup(), -1, STR_TERMINATE);	return PTR_DIFF(p, start);}/**************************************************************************** Start the signing engine if needed. Don't fail signing here.****************************************************************************/static void sessionsetup_start_signing_engine(const auth_serversupplied_info *server_info, char *inbuf){	if (!server_info->guest && !srv_signing_started()) {		/* We need to start the signing engine		 * here but a W2K client sends the old		 * "BSRSPYL " signature instead of the		 * correct one. Subsequent packets will		 * be correct.		 */	       	srv_check_sign_mac(inbuf, False);	}}/**************************************************************************** Send a security blob via a session setup reply.****************************************************************************/static BOOL reply_sesssetup_blob(connection_struct *conn, char *outbuf,				 DATA_BLOB blob, NTSTATUS nt_status){	char *p;	set_message(outbuf,4,0,True);	nt_status = nt_status_squash(nt_status);	SIVAL(outbuf, smb_rcls, NT_STATUS_V(nt_status));	SSVAL(outbuf, smb_vwv0, 0xFF); /* no chaining possible */	SSVAL(outbuf, smb_vwv3, blob.length);	p = smb_buf(outbuf);	/* should we cap this? */	memcpy(p, blob.data, blob.length);	p += blob.length;	p += add_signature( outbuf, p );	set_message_end(outbuf,p);	show_msg(outbuf);	return send_smb(smbd_server_fd(),outbuf);}/**************************************************************************** Do a 'guest' logon, getting back the ****************************************************************************/static NTSTATUS check_guest_password(auth_serversupplied_info **server_info) {	struct auth_context *auth_context;	auth_usersupplied_info *user_info = NULL;		NTSTATUS nt_status;	unsigned char chal[8];	ZERO_STRUCT(chal);	DEBUG(3,("Got anonymous request\n"));	if (!NT_STATUS_IS_OK(nt_status = make_auth_context_fixed(&auth_context, chal))) {		return nt_status;	}	if (!make_user_info_guest(&user_info)) {		(auth_context->free)(&auth_context);		return NT_STATUS_NO_MEMORY;	}		nt_status = auth_context->check_ntlm_password(auth_context, user_info, server_info);	(auth_context->free)(&auth_context);	free_user_info(&user_info);	return nt_status;}#ifdef HAVE_KRB5/****************************************************************************reply to a session setup spnego negotiate packet for kerberos****************************************************************************/static int reply_spnego_kerberos(connection_struct *conn, 				 char *inbuf, char *outbuf,				 int length, int bufsize,				 DATA_BLOB *secblob){	TALLOC_CTX *mem_ctx;	DATA_BLOB ticket;	char *client, *p, *domain;	fstring netbios_domain_name;	struct passwd *pw;	fstring user;	int sess_vuid;	NTSTATUS ret;	PAC_DATA *pac_data;	DATA_BLOB ap_rep, ap_rep_wrapped, response;	auth_serversupplied_info *server_info = NULL;	DATA_BLOB session_key = data_blob(NULL, 0);	uint8 tok_id[2];	DATA_BLOB nullblob = data_blob(NULL, 0);	fstring real_username;	BOOL map_domainuser_to_guest = False;	PAC_LOGON_INFO *logon_info = NULL;	ZERO_STRUCT(ticket);	ZERO_STRUCT(pac_data);	ZERO_STRUCT(ap_rep);	ZERO_STRUCT(ap_rep_wrapped);	ZERO_STRUCT(response);	mem_ctx = talloc_init("reply_spnego_kerberos");	if (mem_ctx == NULL)		return ERROR_NT(NT_STATUS_NO_MEMORY);	if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) {		talloc_destroy(mem_ctx);		return ERROR_NT(NT_STATUS_LOGON_FAILURE);	}	ret = ads_verify_ticket(mem_ctx, lp_realm(), &ticket, &client, &pac_data, &ap_rep, &session_key);	data_blob_free(&ticket);	if (!NT_STATUS_IS_OK(ret)) {		DEBUG(1,("Failed to verify incoming ticket!\n"));			talloc_destroy(mem_ctx);		return ERROR_NT(NT_STATUS_LOGON_FAILURE);	}	DEBUG(3,("Ticket name is [%s]\n", client));	p = strchr_m(client, '@');	if (!p) {		DEBUG(3,("Doesn't look like a valid principal\n"));		data_blob_free(&ap_rep);		data_blob_free(&session_key);		SAFE_FREE(client);		talloc_destroy(mem_ctx);		return ERROR_NT(NT_STATUS_LOGON_FAILURE);	}	*p = 0;	/* save the PAC data if we have it */	if (pac_data) {		logon_info = get_logon_info_from_pac(pac_data);		netsamlogon_cache_store( client, &logon_info->info3 );	}	if (!strequal(p+1, lp_realm())) {		DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1));		if (!lp_allow_trusted_domains()) {			data_blob_free(&ap_rep);			data_blob_free(&session_key);			SAFE_FREE(client);			talloc_destroy(mem_ctx);			return ERROR_NT(NT_STATUS_LOGON_FAILURE);		}	}	/* this gives a fully qualified user name (ie. with full realm).	   that leads to very long usernames, but what else can we do? */	domain = p+1;	if (logon_info && logon_info->info3.hdr_logon_dom.uni_str_len) {		unistr2_to_ascii(netbios_domain_name, &logon_info->info3.uni_logon_dom, -1);		domain = netbios_domain_name;		DEBUG(10, ("Mapped to [%s] (using PAC)\n", domain));	} else {		/* If we have winbind running, we can (and must) shorten the		   username by using the short netbios name. Otherwise we will		   have inconsistent user names. With Kerberos, we get the		   fully qualified realm, with ntlmssp we get the short		   name. And even w2k3 does use ntlmssp if you for example		   connect to an ip address. */		struct winbindd_request wb_request;		struct winbindd_response wb_response;		NSS_STATUS wb_result;		ZERO_STRUCT(wb_request);		ZERO_STRUCT(wb_response);		DEBUG(10, ("Mapping [%s] to short name\n", domain));		fstrcpy(wb_request.domain_name, domain);		wb_result = winbindd_request_response(WINBINDD_DOMAIN_INFO,					     &wb_request, &wb_response);		if (wb_result == NSS_STATUS_SUCCESS) {			fstrcpy(netbios_domain_name,				wb_response.data.domain_info.name);			domain = netbios_domain_name;			DEBUG(10, ("Mapped to [%s] (using Winbind)\n", domain));		} else {			DEBUG(3, ("Could not find short name -- winbind "				  "not running?\n"));		}	}	fstr_sprintf(user, "%s%c%s", domain, *lp_winbind_separator(), client);		/* lookup the passwd struct, create a new user if necessary */	map_username( user );	pw = smb_getpwnam( user, real_username, True );	if (!pw) {		/* this was originally the behavior of Samba 2.2, if a user		   did not have a local uid but has been authenticated, then 		   map them to a guest account */		if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID){ 			map_domainuser_to_guest = True;			fstrcpy(user,lp_guestaccount());			pw = smb_getpwnam( user, real_username, True );		} 		/* extra sanity check that the guest account is valid */		if ( !pw ) {			DEBUG(1,("Username %s is invalid on this system\n", user));			SAFE_FREE(client);			data_blob_free(&ap_rep);			data_blob_free(&session_key);			talloc_destroy(mem_ctx);			return ERROR_NT(NT_STATUS_LOGON_FAILURE);		}	}	/* setup the string used by %U */		sub_set_smb_name( real_username );	reload_services(True);	if ( map_domainuser_to_guest ) {		make_server_info_guest(&server_info);	} else if (logon_info) {		ret = make_server_info_pac(&server_info, real_username, pw, logon_info);		if ( !NT_STATUS_IS_OK(ret) ) {			DEBUG(1,("make_server_info_pac failed!\n"));			SAFE_FREE(client);			data_blob_free(&ap_rep);			data_blob_free(&session_key);			passwd_free(&pw);			talloc_destroy(mem_ctx);			return ERROR_NT(ret);		}	} else {		ret = make_server_info_pw(&server_info, real_username, pw);		if ( !NT_STATUS_IS_OK(ret) ) {			DEBUG(1,("make_server_info_from_pw failed!\n"));			SAFE_FREE(client);			data_blob_free(&ap_rep);			data_blob_free(&session_key);			passwd_free(&pw);			talloc_destroy(mem_ctx);			return ERROR_NT(ret);		}	        /* make_server_info_pw does not set the domain. Without this we end up		 * with the local netbios name in substitutions for %D. */		if (server_info->sam_account != NULL) {			pdb_set_domain(server_info->sam_account, domain, PDB_SET);		}	}	passwd_free(&pw);	/* register_vuid keeps the server info */	/* register_vuid takes ownership of session_key, no need to free after this. 	   A better interface would copy it.... */	sess_vuid = register_vuid(server_info, session_key, nullblob, client);	SAFE_FREE(client);	if (sess_vuid == -1) {		ret = NT_STATUS_LOGON_FAILURE;	} else {		/* current_user_info is changed on new vuid */		reload_services( True );		set_message(outbuf,4,0,True);		SSVAL(outbuf, smb_vwv3, 0);					if (server_info->guest) {			SSVAL(outbuf,smb_vwv2,1);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?