Beispiel #1
0
static NTSTATUS do_ntlm_auth_with_hashes(const char *username,
					const char *domain,
					const unsigned char lm_hash[LM_HASH_LEN],
					const unsigned char nt_hash[NT_HASH_LEN],
					const DATA_BLOB initial_msg,
					const DATA_BLOB challenge_msg,
					DATA_BLOB *auth_msg)
{
	NTSTATUS status;
	NTLMSSP_STATE *ntlmssp_state = NULL;
	DATA_BLOB dummy_msg, reply;

	status = ntlmssp_client_start(&ntlmssp_state);

	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1, ("Could not start NTLMSSP client: %s\n",
			nt_errstr(status)));
		goto done;
	}

	status = ntlmssp_set_username(ntlmssp_state, username);

	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1, ("Could not set username: %s\n",
			nt_errstr(status)));
		goto done;
	}

	status = ntlmssp_set_domain(ntlmssp_state, domain);

	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1, ("Could not set domain: %s\n",
			nt_errstr(status)));
		goto done;
	}

	status = ntlmssp_set_hashes(ntlmssp_state, lm_hash, nt_hash);
        
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1, ("Could not set hashes: %s\n",
			nt_errstr(status)));
		goto done;
	}

	/* We need to get our protocol handler into the right state. So first
	   we ask it to generate the initial message. Actually the client has already
	   sent its own initial message, so we're going to drop this one on the floor.
	   The client might have sent a different message, for example with different
	   negotiation options, but as far as I can tell this won't hurt us. (Unless
	   the client sent a different username or domain, in which case that's their
	   problem for telling us the wrong username or domain.)
	   Since we have a copy of the initial message that the client sent, we could
	   resolve any discrepancies if we had to.
	*/
	dummy_msg = data_blob_null;
	reply = data_blob_null;
	status = ntlmssp_update(ntlmssp_state, dummy_msg, &reply);
	data_blob_free(&dummy_msg);
	data_blob_free(&reply);

	if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
		DEBUG(1, ("Failed to create initial message! [%s]\n",
			nt_errstr(status)));
		goto done;
	}

	/* Now we are ready to handle the server's actual response. */
	status = ntlmssp_update(ntlmssp_state, challenge_msg, &reply);

	if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
		DEBUG(1, ("We didn't get a response to the challenge! [%s]\n",
			nt_errstr(status)));
		data_blob_free(&reply);
		goto done;
	}
	*auth_msg = reply;
	status = NT_STATUS_OK;

done:
	ntlmssp_end(&ntlmssp_state);
	return status;
}
Beispiel #2
0
static NTSTATUS close_remove_share_mode(files_struct *fsp,
					enum file_close_type close_type)
{
	connection_struct *conn = fsp->conn;
	bool delete_file = false;
	bool changed_user = false;
	struct share_mode_lock *lck = NULL;
	NTSTATUS status = NT_STATUS_OK;
	NTSTATUS tmp_status;
	struct file_id id;
	const struct security_unix_token *del_token = NULL;

	/* Ensure any pending write time updates are done. */
	if (fsp->update_write_time_event) {
		update_write_time_handler(server_event_context(),
					fsp->update_write_time_event,
					timeval_current(),
					(void *)fsp);
	}

	/*
	 * Lock the share entries, and determine if we should delete
	 * on close. If so delete whilst the lock is still in effect.
	 * This prevents race conditions with the file being created. JRA.
	 */

	lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL,
				  NULL);

	if (lck == NULL) {
		DEBUG(0, ("close_remove_share_mode: Could not get share mode "
			  "lock for file %s\n", fsp_str_dbg(fsp)));
		status = NT_STATUS_INVALID_PARAMETER;
		goto done;
	}

	if (fsp->write_time_forced) {
		DEBUG(10,("close_remove_share_mode: write time forced "
			"for file %s\n",
			fsp_str_dbg(fsp)));
		set_close_write_time(fsp, lck->changed_write_time);
	} else if (fsp->update_write_time_on_close) {
		/* Someone had a pending write. */
		if (null_timespec(fsp->close_write_time)) {
			DEBUG(10,("close_remove_share_mode: update to current time "
				"for file %s\n",
				fsp_str_dbg(fsp)));
			/* Update to current time due to "normal" write. */
			set_close_write_time(fsp, timespec_current());
		} else {
			DEBUG(10,("close_remove_share_mode: write time pending "
				"for file %s\n",
				fsp_str_dbg(fsp)));
			/* Update to time set on close call. */
			set_close_write_time(fsp, fsp->close_write_time);
		}
	}

	if (!del_share_mode(lck, fsp)) {
		DEBUG(0, ("close_remove_share_mode: Could not delete share "
			  "entry for file %s\n",
			  fsp_str_dbg(fsp)));
	}

	if (fsp->initial_delete_on_close &&
			!is_delete_on_close_set(lck, fsp->name_hash)) {
		bool became_user = False;

		/* Initial delete on close was set and no one else
		 * wrote a real delete on close. */

		if (get_current_vuid(conn) != fsp->vuid) {
			become_user(conn, fsp->vuid);
			became_user = True;
		}
		fsp->delete_on_close = true;
		set_delete_on_close_lck(fsp, lck, True, get_current_utok(conn));
		if (became_user) {
			unbecome_user();
		}
	}

	delete_file = is_delete_on_close_set(lck, fsp->name_hash);

	if (delete_file) {
		int i;
		/* See if others still have the file open via this pathname.
		   If this is the case, then don't delete. If all opens are
		   POSIX delete now. */
		for (i=0; i<lck->num_share_modes; i++) {
			struct share_mode_entry *e = &lck->share_modes[i];
			if (is_valid_share_mode_entry(e) &&
					e->name_hash == fsp->name_hash) {
				if (fsp->posix_open && (e->flags & SHARE_MODE_FLAG_POSIX_OPEN)) {
					continue;
				}
				delete_file = False;
				break;
			}
		}
	}

	/* Notify any deferred opens waiting on this close. */
	notify_deferred_opens(conn->sconn->msg_ctx, lck);
	reply_to_oplock_break_requests(fsp);

	/*
	 * NT can set delete_on_close of the last open
	 * reference to a file.
	 */

	if (!(close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE) ||
			!delete_file) {
		TALLOC_FREE(lck);
		return NT_STATUS_OK;
	}

	/*
	 * Ok, we have to delete the file
	 */

	DEBUG(5,("close_remove_share_mode: file %s. Delete on close was set "
		 "- deleting file.\n", fsp_str_dbg(fsp)));

	/*
	 * Don't try to update the write time when we delete the file
	 */
	fsp->update_write_time_on_close = false;

	del_token = get_delete_on_close_token(lck, fsp->name_hash);
	SMB_ASSERT(del_token != NULL);

	if (!unix_token_equal(del_token, get_current_utok(conn))) {
		/* Become the user who requested the delete. */

		DEBUG(5,("close_remove_share_mode: file %s. "
			"Change user to uid %u\n",
			fsp_str_dbg(fsp),
			(unsigned int)del_token->uid));

		if (!push_sec_ctx()) {
			smb_panic("close_remove_share_mode: file %s. failed to push "
				  "sec_ctx.\n");
		}

		set_sec_ctx(del_token->uid,
			    del_token->gid,
			    del_token->ngroups,
			    del_token->groups,
			    NULL);

		changed_user = true;
	}

	/* We can only delete the file if the name we have is still valid and
	   hasn't been renamed. */

	tmp_status = vfs_stat_fsp(fsp);
	if (!NT_STATUS_IS_OK(tmp_status)) {
		DEBUG(5,("close_remove_share_mode: file %s. Delete on close "
			 "was set and stat failed with error %s\n",
			 fsp_str_dbg(fsp), nt_errstr(tmp_status)));
		/*
		 * Don't save the errno here, we ignore this error
		 */
		goto done;
	}

	id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st);

	if (!file_id_equal(&fsp->file_id, &id)) {
		DEBUG(5,("close_remove_share_mode: file %s. Delete on close "
			 "was set and dev and/or inode does not match\n",
			 fsp_str_dbg(fsp)));
		DEBUG(5,("close_remove_share_mode: file %s. stored file_id %s, "
			 "stat file_id %s\n",
			 fsp_str_dbg(fsp),
			 file_id_string_tos(&fsp->file_id),
			 file_id_string_tos(&id)));
		/*
		 * Don't save the errno here, we ignore this error
		 */
		goto done;
	}

	if ((conn->fs_capabilities & FILE_NAMED_STREAMS)
	    && !is_ntfs_stream_smb_fname(fsp->fsp_name)) {

		status = delete_all_streams(conn, fsp->fsp_name->base_name);

		if (!NT_STATUS_IS_OK(status)) {
			DEBUG(5, ("delete_all_streams failed: %s\n",
				  nt_errstr(status)));
			goto done;
		}
	}


	if (SMB_VFS_UNLINK(conn, fsp->fsp_name) != 0) {
		/*
		 * This call can potentially fail as another smbd may
		 * have had the file open with delete on close set and
		 * deleted it when its last reference to this file
		 * went away. Hence we log this but not at debug level
		 * zero.
		 */

		DEBUG(5,("close_remove_share_mode: file %s. Delete on close "
			 "was set and unlink failed with error %s\n",
			 fsp_str_dbg(fsp), strerror(errno)));

		status = map_nt_error_from_unix(errno);
	}

	/* As we now have POSIX opens which can unlink
 	 * with other open files we may have taken
 	 * this code path with more than one share mode
 	 * entry - ensure we only delete once by resetting
 	 * the delete on close flag. JRA.
 	 */

	fsp->delete_on_close = false;
	set_delete_on_close_lck(fsp, lck, false, NULL);

 done:

	if (changed_user) {
		/* unbecome user. */
		pop_sec_ctx();
	}

	TALLOC_FREE(lck);

	if (delete_file) {
		/*
		 * Do the notification after we released the share
		 * mode lock. Inside notify_fname we take out another
		 * tdb lock. With ctdb also accessing our databases,
		 * this can lead to deadlocks. Putting this notify
		 * after the TALLOC_FREE(lck) above we avoid locking
		 * two records simultaneously. Notifies are async and
		 * informational only, so calling the notify_fname
		 * without holding the share mode lock should not do
		 * any harm.
		 */
		notify_fname(conn, NOTIFY_ACTION_REMOVED,
			     FILE_NOTIFY_CHANGE_FILE_NAME,
			     fsp->fsp_name->base_name);
	}

	return status;
}
Beispiel #3
0
static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp,
				enum file_close_type close_type)
{
	struct share_mode_lock *lck = NULL;
	bool delete_dir = False;
	NTSTATUS status = NT_STATUS_OK;
	NTSTATUS status1 = NT_STATUS_OK;
	const struct security_unix_token *del_token = NULL;

	/*
	 * NT can set delete_on_close of the last open
	 * reference to a directory also.
	 */

	lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL,
				  NULL);

	if (lck == NULL) {
		DEBUG(0, ("close_directory: Could not get share mode lock for "
			  "%s\n", fsp_str_dbg(fsp)));
		status = NT_STATUS_INVALID_PARAMETER;
		goto out;
	}

	if (!del_share_mode(lck, fsp)) {
		DEBUG(0, ("close_directory: Could not delete share entry for "
			  "%s\n", fsp_str_dbg(fsp)));
	}

	if (fsp->initial_delete_on_close) {
		bool became_user = False;

		/* Initial delete on close was set - for
		 * directories we don't care if anyone else
		 * wrote a real delete on close. */

		if (get_current_vuid(fsp->conn) != fsp->vuid) {
			become_user(fsp->conn, fsp->vuid);
			became_user = True;
		}
		send_stat_cache_delete_message(fsp->conn->sconn->msg_ctx,
					       fsp->fsp_name->base_name);
		set_delete_on_close_lck(fsp, lck, true,
				get_current_utok(fsp->conn));
		fsp->delete_on_close = true;
		if (became_user) {
			unbecome_user();
		}
	}

	del_token = get_delete_on_close_token(lck, fsp->name_hash);
	delete_dir = (del_token != NULL);

	if (delete_dir) {
		int i;
		/* See if others still have the dir open. If this is the
		 * case, then don't delete. If all opens are POSIX delete now. */
		for (i=0; i<lck->num_share_modes; i++) {
			struct share_mode_entry *e = &lck->share_modes[i];
			if (is_valid_share_mode_entry(e) &&
					e->name_hash == fsp->name_hash) {
				if (fsp->posix_open && (e->flags & SHARE_MODE_FLAG_POSIX_OPEN)) {
					continue;
				}
				delete_dir = False;
				break;
			}
		}
	}

	if ((close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE) &&
				delete_dir) {
	
		/* Become the user who requested the delete. */

		if (!push_sec_ctx()) {
			smb_panic("close_directory: failed to push sec_ctx.\n");
		}

		set_sec_ctx(del_token->uid,
				del_token->gid,
				del_token->ngroups,
				del_token->groups,
				NULL);

		TALLOC_FREE(lck);

		status = rmdir_internals(talloc_tos(), fsp);

		DEBUG(5,("close_directory: %s. Delete on close was set - "
			 "deleting directory returned %s.\n",
			 fsp_str_dbg(fsp), nt_errstr(status)));

		/* unbecome user. */
		pop_sec_ctx();

		/*
		 * Ensure we remove any change notify requests that would
		 * now fail as the directory has been deleted.
		 */

		if(NT_STATUS_IS_OK(status)) {
			remove_pending_change_notify_requests_by_fid(fsp, NT_STATUS_DELETE_PENDING);
		}
	} else {
		TALLOC_FREE(lck);
		remove_pending_change_notify_requests_by_fid(
			fsp, NT_STATUS_OK);
	}

	status1 = fd_close(fsp);

	if (!NT_STATUS_IS_OK(status1)) {
		DEBUG(0, ("Could not close dir! fname=%s, fd=%d, err=%d=%s\n",
			  fsp_str_dbg(fsp), fsp->fh->fd, errno,
			  strerror(errno)));
	}

	/*
	 * Do the code common to files and directories.
	 */
	close_filestruct(fsp);
	file_free(req, fsp);

 out:
	TALLOC_FREE(lck);
	if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(status1)) {
		status = status1;
	}
	return status;
}
Beispiel #4
0
bool torture_domain_list(struct torture_context *torture)
{
	bool ret = true;
	NTSTATUS status;
	TALLOC_CTX *mem_ctx = NULL;
	struct dcerpc_binding *binding;
	struct libnet_context *ctx;
	struct libnet_DomainList r;
	int i;

	status = torture_rpc_binding(torture, &binding);
	if (!NT_STATUS_IS_OK(status)) {
		return false;
	}

	ctx = libnet_context_init(torture->ev, torture->lp_ctx);
	if (ctx == NULL) {
		torture_comment(torture, "failed to create libnet context\n");
		ret = false;
		goto done;
	}

	ctx->cred = cmdline_credentials;

	mem_ctx = talloc_init("torture_domain_close_samr");

	/*
	 * querying the domain list using default buffer size
	 */

	ZERO_STRUCT(r);
	r.in.hostname = dcerpc_binding_get_string_option(binding, "host");

	status = libnet_DomainList(ctx, mem_ctx, &r);
	if (!NT_STATUS_IS_OK(status)) {
		ret = false;
		goto done;
	}

	torture_comment(torture, "Received list or domains (everything in one piece):\n");

	for (i = 0; i < r.out.count; i++) {
		torture_comment(torture, "Name[%d]: %s\n", i, r.out.domains[i].name);
	}

	/*
	 * querying the domain list using specified (much smaller) buffer size
	 */

	ctx->samr.buf_size = 32;

	ZERO_STRUCT(r);
	r.in.hostname = dcerpc_binding_get_string_option(binding, "host");

	status = libnet_DomainList(ctx, mem_ctx, &r);
	if (!NT_STATUS_IS_OK(status)) {
		ret = false;
		goto done;
	}

	torture_comment(torture, "Received list or domains (collected in more than one round):\n");

	for (i = 0; i < r.out.count; i++) {
		torture_comment(torture, "Name[%d]: %s\n", i, r.out.domains[i].name);
	}

done:
	torture_comment(torture, "\nStatus: %s\n", nt_errstr(status));

	talloc_free(mem_ctx);
	talloc_free(ctx);
	return ret;
}
static bool get_rpc_shares(struct cli_state *cli,
			   void (*fn)(const char *, uint32, const char *, void *),
			   void *state)
{
	NTSTATUS status;
	struct rpc_pipe_client *pipe_hnd = NULL;
	TALLOC_CTX *mem_ctx;
	WERROR werr;
	struct srvsvc_NetShareInfoCtr info_ctr;
	struct srvsvc_NetShareCtr1 ctr1;
	int i;
	uint32_t resume_handle = 0;
	uint32_t total_entries = 0;
	struct dcerpc_binding_handle *b;

	mem_ctx = talloc_new(NULL);
	if (mem_ctx == NULL) {
		DEBUG(0, ("talloc_new failed\n"));
		return False;
	}

	status = cli_rpc_pipe_open_noauth(cli, &ndr_table_srvsvc.syntax_id,
					  &pipe_hnd);

	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(10, ("Could not connect to srvsvc pipe: %s\n",
			   nt_errstr(status)));
		TALLOC_FREE(mem_ctx);
		return False;
	}

	b = pipe_hnd->binding_handle;

	ZERO_STRUCT(info_ctr);
	ZERO_STRUCT(ctr1);

	info_ctr.level = 1;
	info_ctr.ctr.ctr1 = &ctr1;

	status = dcerpc_srvsvc_NetShareEnumAll(b, mem_ctx,
					       pipe_hnd->desthost,
					       &info_ctr,
					       0xffffffff,
					       &total_entries,
					       &resume_handle,
					       &werr);

	if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(werr)) {
		TALLOC_FREE(mem_ctx);
		TALLOC_FREE(pipe_hnd);
		return False;
	}

	for (i=0; i<total_entries; i++) {
		struct srvsvc_NetShareInfo1 info = info_ctr.ctr.ctr1->array[i];
		fn(info.name, info.type, info.comment, state);
	}

	TALLOC_FREE(mem_ctx);
	TALLOC_FREE(pipe_hnd);
	return True;
}
Beispiel #6
0
Datei: auth.c Projekt: aosm/samba
static NTSTATUS check_ntlm_password(const struct auth_context *auth_context,
				    const struct auth_usersupplied_info *user_info, 
				    struct auth_serversupplied_info **server_info)
{
	/* if all the modules say 'not for me' this is reasonable */
	NTSTATUS nt_status = NT_STATUS_NO_SUCH_USER;
	const char *unix_username;
	auth_methods *auth_method;
	TALLOC_CTX *mem_ctx;

	if (!user_info || !auth_context || !server_info)
		return NT_STATUS_LOGON_FAILURE;

	DEBUG(3, ("check_ntlm_password:  Checking password for unmapped user [%s]\\[%s]@[%s] with the new password interface\n", 
		  user_info->client_domain, user_info->smb_name, user_info->wksta_name));

	DEBUG(3, ("check_ntlm_password:  mapped user is: [%s]\\[%s]@[%s]\n", 
		  user_info->domain, user_info->internal_username, user_info->wksta_name));

	if (auth_context->challenge.length != 8) {
		DEBUG(0, ("check_ntlm_password:  Invalid challenge stored for this auth context - cannot continue\n"));
		return NT_STATUS_LOGON_FAILURE;
	}

	if (auth_context->challenge_set_by)
		DEBUG(10, ("check_ntlm_password: auth_context challenge created by %s\n",
					auth_context->challenge_set_by));

	DEBUG(10, ("challenge is: \n"));
	dump_data(5, (const char *)auth_context->challenge.data, auth_context->challenge.length);

#ifdef DEBUG_PASSWORD
	DEBUG(100, ("user_info has passwords of length %d and %d\n", 
		    (int)user_info->lm_resp.length, (int)user_info->nt_resp.length));
	DEBUG(100, ("lm:\n"));
	dump_data(100, (const char *)user_info->lm_resp.data, user_info->lm_resp.length);
	DEBUG(100, ("nt:\n"));
	dump_data(100, (const char *)user_info->nt_resp.data, user_info->nt_resp.length);
#endif

	/* This needs to be sorted:  If it doesn't match, what should we do? */
  	if (!check_domain_match(user_info->smb_name, user_info->domain))
		return NT_STATUS_LOGON_FAILURE;

	for (auth_method = auth_context->auth_method_list;auth_method; auth_method = auth_method->next) {
		NTSTATUS result;
		
		mem_ctx = talloc_init("%s authentication for user %s\\%s", auth_method->name, 
					    user_info->domain, user_info->smb_name);

		result = auth_method->auth(auth_context, auth_method->private_data, mem_ctx, user_info, server_info);

		/* check if the module did anything */
		if ( NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_NOT_IMPLEMENTED) ) {
			DEBUG(10,("check_ntlm_password: %s had nothing to say\n", auth_method->name));
			talloc_destroy(mem_ctx);
			continue;
		}

		nt_status = result;

		if (NT_STATUS_IS_OK(nt_status)) {
			DEBUG(3, ("check_ntlm_password: %s authentication for user [%s] succeeded\n", 
				  auth_method->name, user_info->smb_name));
		} else {
			DEBUG(5, ("check_ntlm_password: %s authentication for user [%s] FAILED with error %s\n", 
				  auth_method->name, user_info->smb_name, nt_errstr(nt_status)));
		}

		talloc_destroy(mem_ctx);

		if ( NT_STATUS_IS_OK(nt_status))
		{
				break;			
		}
	}

	/* successful authentication */
	
	if (NT_STATUS_IS_OK(nt_status)) {
		unix_username = (*server_info)->unix_name;
		if (!(*server_info)->guest) {
			/* We might not be root if we are an RPC call */
			become_root();
			nt_status = smb_pam_accountcheck(unix_username);
			unbecome_root();
			
			if (NT_STATUS_IS_OK(nt_status)) {
				DEBUG(5, ("check_ntlm_password:  PAM Account for user [%s] succeeded\n", 
					  unix_username));
			} else {
				DEBUG(3, ("check_ntlm_password:  PAM Account for user [%s] FAILED with error %s\n", 
					  unix_username, nt_errstr(nt_status)));
			} 
		}
		
		if (NT_STATUS_IS_OK(nt_status)) {
			DEBUG((*server_info)->guest ? 5 : 2, 
			      ("check_ntlm_password:  %sauthentication for user [%s] -> [%s] -> [%s] succeeded\n", 
			       (*server_info)->guest ? "guest " : "", 
			       user_info->smb_name, 
			       user_info->internal_username, 
			       unix_username));
		}
		
		return nt_status;
	}
	
	/* failed authentication; check for guest lapping */
	
	DEBUG(2, ("check_ntlm_password:  Authentication for user [%s] -> [%s] FAILED with error %s\n", 
		  user_info->smb_name, user_info->internal_username, 
		  nt_errstr(nt_status)));
	ZERO_STRUCTP(server_info); 
	
	return nt_status;
}
Beispiel #7
0
static NTSTATUS make_new_session_info_system(TALLOC_CTX *mem_ctx,
					    struct auth_session_info **session_info)
{
	NTSTATUS status;
	struct auth_serversupplied_info *server_info;
	TALLOC_CTX *tmp_ctx;

	tmp_ctx = talloc_stackframe();
	if (tmp_ctx == NULL) {
		return NT_STATUS_NO_MEMORY;
	}

	server_info = make_server_info(tmp_ctx);
	if (!server_info) {
		status = NT_STATUS_NO_MEMORY;
		DEBUG(0, ("failed making server_info\n"));
		goto done;
	}

	server_info->info3 = talloc_zero(server_info, struct netr_SamInfo3);
	if (!server_info->info3) {
		status = NT_STATUS_NO_MEMORY;
		DEBUG(0, ("talloc failed setting info3\n"));
		goto done;
	}

	status = get_system_info3(server_info, server_info->info3);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(0, ("Failed creating system info3 with %s\n",
			  nt_errstr(status)));
		goto done;
	}

	server_info->utok.uid = sec_initial_uid();
	server_info->utok.gid = sec_initial_gid();
	server_info->unix_name = talloc_asprintf(server_info,
						 "NT AUTHORITY%cSYSTEM",
						 *lp_winbind_separator());

	if (!server_info->unix_name) {
		status = NT_STATUS_NO_MEMORY;
		DEBUG(0, ("talloc_asprintf failed setting unix_name\n"));
		goto done;
	}

	server_info->security_token = talloc_zero(server_info, struct security_token);
	if (!server_info->security_token) {
		status = NT_STATUS_NO_MEMORY;
		DEBUG(0, ("talloc failed setting security token\n"));
		goto done;
	}

	status = add_sid_to_array_unique(server_info->security_token->sids,
					 &global_sid_System,
					 &server_info->security_token->sids,
					 &server_info->security_token->num_sids);
	if (!NT_STATUS_IS_OK(status)) {
		goto done;
	}

	/* SYSTEM has all privilages */
	server_info->security_token->privilege_mask = ~0;

	/* Now turn the server_info into a session_info with the full token etc */
	status = create_local_token(mem_ctx, server_info, NULL, "SYSTEM", session_info);
	talloc_free(server_info);

	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(0, ("create_local_token failed: %s\n",
			  nt_errstr(status)));
		goto done;
	}

	talloc_steal(mem_ctx, *session_info);

done:
	TALLOC_FREE(tmp_ctx);
	return status;
}
Beispiel #8
0
/**
 * Check a user's Plaintext, LM or NTLM password.
 *
 * Check a user's password, as given in the user_info struct and return various
 * interesting details in the server_info struct.
 *
 * This function does NOT need to be in a become_root()/unbecome_root() pair
 * as it makes the calls itself when needed.
 *
 * The return value takes precedence over the contents of the server_info 
 * struct.  When the return is other than NT_STATUS_OK the contents 
 * of that structure is undefined.
 *
 * @param user_info Contains the user supplied components, including the passwords.
 *                  Must be created with make_user_info() or one of its wrappers.
 *
 * @param auth_context Supplies the challenges and some other data. 
 *                  Must be created with make_auth_context(), and the challenges should be 
 *                  filled in, either at creation or by calling the challenge geneation 
 *                  function auth_get_challenge().  
 *
 * @param pserver_info If successful, contains information about the authentication,
 *                     including a struct samu struct describing the user.
 *
 * @param pauthoritative Indicates if the result should be treated as final
 *                       result.
 *
 * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
 *
 **/
NTSTATUS auth_check_ntlm_password(TALLOC_CTX *mem_ctx,
				  const struct auth_context *auth_context,
				  const struct auth_usersupplied_info *user_info,
				  struct auth_serversupplied_info **pserver_info,
				  uint8_t *pauthoritative)
{
	TALLOC_CTX *frame;
	const char *auth_method_name = "";
	/* if all the modules say 'not for me' this is reasonable */
	NTSTATUS nt_status = NT_STATUS_NOT_IMPLEMENTED;
	const char *unix_username;
	auth_methods *auth_method;
	struct auth_serversupplied_info *server_info = NULL;
	struct dom_sid sid = {0};

	if (user_info == NULL || auth_context == NULL || pserver_info == NULL) {
		return NT_STATUS_LOGON_FAILURE;
	}

	frame = talloc_stackframe();

	*pauthoritative = 1;

	DEBUG(3, ("check_ntlm_password:  Checking password for unmapped user [%s]\\[%s]@[%s] with the new password interface\n", 
		  user_info->client.domain_name, user_info->client.account_name, user_info->workstation_name));

	DEBUG(3, ("check_ntlm_password:  mapped user is: [%s]\\[%s]@[%s]\n", 
		  user_info->mapped.domain_name, user_info->mapped.account_name, user_info->workstation_name));

	if (auth_context->challenge.length != 8) {
		DEBUG(0, ("check_ntlm_password:  Invalid challenge stored for this auth context - cannot continue\n"));
		nt_status = NT_STATUS_LOGON_FAILURE;
		goto fail;
	}

	if (auth_context->challenge_set_by)
		DEBUG(10, ("check_ntlm_password: auth_context challenge created by %s\n",
					auth_context->challenge_set_by));

	DEBUG(10, ("challenge is: \n"));
	dump_data(5, auth_context->challenge.data, auth_context->challenge.length);

#ifdef DEBUG_PASSWORD
	DEBUG(100, ("user_info has passwords of length %d and %d\n", 
		    (int)user_info->password.response.lanman.length, (int)user_info->password.response.nt.length));
	DEBUG(100, ("lm:\n"));
	dump_data(100, user_info->password.response.lanman.data, user_info->password.response.lanman.length);
	DEBUG(100, ("nt:\n"));
	dump_data(100, user_info->password.response.nt.data, user_info->password.response.nt.length);
#endif

	/* This needs to be sorted:  If it doesn't match, what should we do? */
	if (!check_domain_match(user_info->client.account_name,
				user_info->mapped.domain_name)) {
		nt_status = NT_STATUS_LOGON_FAILURE;
		goto fail;
	}

	for (auth_method = auth_context->auth_method_list;auth_method; auth_method = auth_method->next) {

		auth_method_name = auth_method->name;

		nt_status = auth_method->auth(auth_context,
					      auth_method->private_data,
					      talloc_tos(),
					      user_info,
					      &server_info);

		if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_NOT_IMPLEMENTED)) {
			break;
		}

		DBG_DEBUG("%s had nothing to say\n", auth_method->name);
	}

	if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NOT_IMPLEMENTED)) {
		*pauthoritative = 0;
		nt_status = NT_STATUS_NO_SUCH_USER;
	}

	if (!NT_STATUS_IS_OK(nt_status)) {
		DBG_INFO("%s authentication for user [%s] FAILED with "
			 "error %s, authoritative=%u\n",
			 auth_method_name,
			 user_info->client.account_name,
			 nt_errstr(nt_status),
			 *pauthoritative);
		goto fail;
	}

	DBG_NOTICE("%s authentication for user [%s] succeeded\n",
		   auth_method_name, user_info->client.account_name);

	unix_username = server_info->unix_name;

	/* We skip doing this step if the caller asked us not to */
	if (!(user_info->flags & USER_INFO_INFO3_AND_NO_AUTHZ)
	    && !(server_info->guest)) {
		const char *rhost;

		if (tsocket_address_is_inet(user_info->remote_host, "ip")) {
			rhost = tsocket_address_inet_addr_string(
				user_info->remote_host, talloc_tos());
			if (rhost == NULL) {
				nt_status = NT_STATUS_NO_MEMORY;
				goto fail;
			}
		} else {
			rhost = "127.0.0.1";
		}

		/* We might not be root if we are an RPC call */
		become_root();
		nt_status = smb_pam_accountcheck(unix_username, rhost);
		unbecome_root();

		if (NT_STATUS_IS_OK(nt_status)) {
			DEBUG(5, ("check_ntlm_password:  PAM Account for user [%s] "
				  "succeeded\n", unix_username));
		} else {
			DEBUG(3, ("check_ntlm_password:  PAM Account for user [%s] "
				  "FAILED with error %s\n",
				  unix_username, nt_errstr(nt_status)));
		}
	}

	if (!NT_STATUS_IS_OK(nt_status)) {
		goto fail;
	}

	nt_status = get_user_sid_info3_and_extra(server_info->info3,
						 &server_info->extra,
						 &sid);
	if (!NT_STATUS_IS_OK(nt_status)) {
		sid = (struct dom_sid) {0};
	}

	log_authentication_event(NULL, NULL,
				 user_info, nt_status,
				 server_info->info3->base.logon_domain.string,
				 server_info->info3->base.account_name.string,
				 unix_username, &sid);

	DEBUG(server_info->guest ? 5 : 2,
	      ("check_ntlm_password:  %sauthentication for user "
	       "[%s] -> [%s] -> [%s] succeeded\n",
	       server_info->guest ? "guest " : "",
	       user_info->client.account_name,
	       user_info->mapped.account_name,
	       unix_username));

	*pserver_info = talloc_move(mem_ctx, &server_info);

	TALLOC_FREE(frame);
	return NT_STATUS_OK;

fail:

	/* failed authentication; check for guest lapping */

	/*
	 * Please try not to change this string, it is probably in use
	 * in audit logging tools
	 */
	DEBUG(2, ("check_ntlm_password:  Authentication for user "
		  "[%s] -> [%s] FAILED with error %s, authoritative=%u\n",
		  user_info->client.account_name, user_info->mapped.account_name,
		  nt_errstr(nt_status), *pauthoritative));

	log_authentication_event(NULL, NULL, user_info, nt_status, NULL, NULL, NULL, NULL);

	ZERO_STRUCTP(pserver_info);

	TALLOC_FREE(frame);

	return nt_status;
}
Beispiel #9
0
static bool process_request_pdu(struct pipes_struct *p, struct ncacn_packet *pkt)
{
	NTSTATUS status;
	DATA_BLOB data;

	if (!p->pipe_bound) {
		DEBUG(0,("process_request_pdu: rpc request with no bind.\n"));
		set_incoming_fault(p);
		return False;
	}

	/* Store the opnum */
	p->opnum = pkt->u.request.opnum;

	status = dcesrv_auth_request(&p->auth, pkt, &p->in_data.pdu);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(0, ("Failed to check packet auth. (%s)\n",
			  nt_errstr(status)));
		set_incoming_fault(p);
		return false;
	}

	data = pkt->u.request.stub_and_verifier;

	/*
	 * Check the data length doesn't go over the 15Mb limit.
	 * increased after observing a bug in the Windows NT 4.0 SP6a
	 * spoolsv.exe when the response to a GETPRINTERDRIVER2 RPC
	 * will not fit in the initial buffer of size 0x1068   --jerry 22/01/2002
	 */

	if (p->in_data.data.length + data.length > MAX_RPC_DATA_SIZE) {
		DEBUG(0, ("process_request_pdu: "
			  "rpc data buffer too large (%u) + (%u)\n",
			  (unsigned int)p->in_data.data.length,
			  (unsigned int)data.length));
		set_incoming_fault(p);
		return False;
	}

	/*
	 * Append the data portion into the buffer and return.
	 */

	if (data.length) {
		if (!data_blob_append(p->mem_ctx, &p->in_data.data,
					  data.data, data.length)) {
			DEBUG(0, ("Unable to append data size %u "
				  "to parse buffer of size %u.\n",
				  (unsigned int)data.length,
				  (unsigned int)p->in_data.data.length));
			set_incoming_fault(p);
			return False;
		}
	}

	if (pkt->pfc_flags & DCERPC_PFC_FLAG_LAST) {
		bool ret = False;
		/*
		 * Ok - we finally have a complete RPC stream.
		 * Call the rpc command to process it.
		 */

		/*
		 * Process the complete data stream here.
		 */
		if (pipe_init_outgoing_data(p)) {
			ret = api_pipe_request(p, pkt);
		}

		return ret;
	}

	return True;
}
Beispiel #10
0
/*
 main server.
*/
static int binary_smbd_main(const char *binary_name, int argc, const char *argv[])
{
	bool opt_daemon = false;
	bool opt_interactive = false;
	int opt;
	poptContext pc;
#define _MODULE_PROTO(init) extern NTSTATUS init(void);
	STATIC_service_MODULES_PROTO;
	init_module_fn static_init[] = { STATIC_service_MODULES };
	init_module_fn *shared_init;
	struct tevent_context *event_ctx;
	uint16_t stdin_event_flags;
	NTSTATUS status;
	const char *model = "standard";
	int max_runtime = 0;
	enum {
		OPT_DAEMON = 1000,
		OPT_INTERACTIVE,
		OPT_PROCESS_MODEL,
		OPT_SHOW_BUILD
	};
	struct poptOption long_options[] = {
		POPT_AUTOHELP
		{"daemon", 'D', POPT_ARG_NONE, NULL, OPT_DAEMON,
		 "Become a daemon (default)", NULL },
		{"interactive",	'i', POPT_ARG_NONE, NULL, OPT_INTERACTIVE,
		 "Run interactive (not a daemon)", NULL},
		{"model", 'M', POPT_ARG_STRING,	NULL, OPT_PROCESS_MODEL, 
		 "Select process model", "MODEL"},
		{"maximum-runtime",0, POPT_ARG_INT, &max_runtime, 0, 
		 "set maximum runtime of the server process, till autotermination", "seconds"},
		{"show-build", 'b', POPT_ARG_NONE, NULL, OPT_SHOW_BUILD, "show build info", NULL },
		POPT_COMMON_SAMBA
		POPT_COMMON_VERSION
		{ NULL }
	};

	pc = poptGetContext(binary_name, argc, argv, long_options, 0);
	while((opt = poptGetNextOpt(pc)) != -1) {
		switch(opt) {
		case OPT_DAEMON:
			opt_daemon = true;
			break;
		case OPT_INTERACTIVE:
			opt_interactive = true;
			break;
		case OPT_PROCESS_MODEL:
			model = poptGetOptArg(pc);
			break;
		case OPT_SHOW_BUILD:
			show_build();
			break;
		default:
			fprintf(stderr, "\nInvalid option %s: %s\n\n",
				  poptBadOption(pc, 0), poptStrerror(opt));
			poptPrintUsage(pc, stderr, 0);
			return 1;
		}
	}

	if (opt_daemon && opt_interactive) {
		fprintf(stderr,"\nERROR: "
			  "Option -i|--interactive is not allowed together with -D|--daemon\n\n");
		poptPrintUsage(pc, stderr, 0);
		return 1;
	} else if (!opt_interactive) {
		/* default is --daemon */
		opt_daemon = true;
	}

	poptFreeContext(pc);

	setup_logging(binary_name, opt_interactive?DEBUG_STDOUT:DEBUG_FILE);
	setup_signals();

	/* we want total control over the permissions on created files,
	   so set our umask to 0 */
	umask(0);

	DEBUG(0,("%s version %s started.\n", binary_name, SAMBA_VERSION_STRING));
	DEBUGADD(0,("Copyright Andrew Tridgell and the Samba Team 1992-2013\n"));

	if (sizeof(uint16_t) < 2 || sizeof(uint32_t) < 4 || sizeof(uint64_t) < 8) {
		DEBUG(0,("ERROR: Samba is not configured correctly for the word size on your machine\n"));
		DEBUGADD(0,("sizeof(uint16_t) = %u, sizeof(uint32_t) %u, sizeof(uint64_t) = %u\n",
			    (unsigned int)sizeof(uint16_t), (unsigned int)sizeof(uint32_t), (unsigned int)sizeof(uint64_t)));
		return 1;
	}

	if (opt_daemon) {
		DEBUG(3,("Becoming a daemon.\n"));
		become_daemon(true, false, false);
	}

	cleanup_tmp_files(cmdline_lp_ctx);

	if (!directory_exist(lpcfg_lockdir(cmdline_lp_ctx))) {
		mkdir(lpcfg_lockdir(cmdline_lp_ctx), 0755);
	}

	pidfile_create(lpcfg_piddir(cmdline_lp_ctx), binary_name);

	/* Set up a database to hold a random seed, in case we don't
	 * have /dev/urandom */
	if (!randseed_init(talloc_autofree_context(), cmdline_lp_ctx)) {
		return 1;
	}

	if (lpcfg_server_role(cmdline_lp_ctx) == ROLE_ACTIVE_DIRECTORY_DC) {
		if (!open_schannel_session_store(talloc_autofree_context(), cmdline_lp_ctx)) {
			DEBUG(0,("ERROR: Samba cannot open schannel store for secured NETLOGON operations.\n"));
			exit(1);
		}
	}

	gensec_init(); /* FIXME: */

	ntptr_init();	/* FIXME: maybe run this in the initialization function 
						of the spoolss RPC server instead? */

	ntvfs_init(cmdline_lp_ctx); 	/* FIXME: maybe run this in the initialization functions 
						of the SMB[,2] server instead? */

	process_model_init(cmdline_lp_ctx); 

	shared_init = load_samba_modules(NULL, "service");

	run_init_functions(static_init);
	run_init_functions(shared_init);

	talloc_free(shared_init);
	
	/* the event context is the top level structure in smbd. Everything else
	   should hang off that */
	event_ctx = s4_event_context_init(talloc_autofree_context());

	if (event_ctx == NULL) {
		DEBUG(0,("Initializing event context failed\n"));
		return 1;
	}

	if (opt_interactive) {
		/* terminate when stdin goes away */
		stdin_event_flags = TEVENT_FD_READ;
	} else {
		/* stay alive forever */
		stdin_event_flags = 0;
	}

	/* catch EOF on stdin */
#ifdef SIGTTIN
	signal(SIGTTIN, SIG_IGN);
#endif
	tevent_add_fd(event_ctx, event_ctx, 0, stdin_event_flags,
		      server_stdin_handler,
		      discard_const(binary_name));

	if (max_runtime) {
		DEBUG(0,("Called with maxruntime %d - current ts %llu\n",
		      max_runtime, (unsigned long long) time(NULL)));
		tevent_add_timer(event_ctx, event_ctx,
				 timeval_current_ofs(max_runtime, 0),
				 max_runtime_handler,
				 discard_const(binary_name));
	}

	if (lpcfg_server_role(cmdline_lp_ctx) != ROLE_ACTIVE_DIRECTORY_DC
	    && !lpcfg_parm_bool(cmdline_lp_ctx, NULL, "server role check", "inhibit", false)
	    && !str_list_check_ci(lpcfg_server_services(cmdline_lp_ctx), "smb") 
	    && !str_list_check_ci(lpcfg_dcerpc_endpoint_servers(cmdline_lp_ctx), "remote")
	    && !str_list_check_ci(lpcfg_dcerpc_endpoint_servers(cmdline_lp_ctx), "mapiproxy")) {
		DEBUG(0, ("At this time the 'samba' binary should only be used for either:\n"));
		DEBUGADD(0, ("'server role = active directory domain controller' or to access the ntvfs file server with 'server services = +smb' or the rpc proxy with 'dcerpc endpoint servers = remote'\n"));
		DEBUGADD(0, ("You should start smbd/nmbd/winbindd instead for domain member and standalone file server tasks\n"));
		exit(1);
	};

	prime_ldb_databases(event_ctx);

	status = setup_parent_messaging(event_ctx, cmdline_lp_ctx);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(0,("Failed to setup parent messaging - %s\n", nt_errstr(status)));
		return 1;
	}

	DEBUG(0,("%s: using '%s' process model\n", binary_name, model));

	status = server_service_startup(event_ctx, cmdline_lp_ctx, model, 
					lpcfg_server_services(cmdline_lp_ctx));
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(0,("Starting Services failed - %s\n", nt_errstr(status)));
		return 1;
	}

	/* wait for events - this is where smbd sits for most of its
	   life */
	tevent_loop_wait(event_ctx);

	/* as everything hangs off this event context, freeing it
	   should initiate a clean shutdown of all services */
	talloc_free(event_ctx);

	return 0;
}
Beispiel #11
0
bool torture_net_become_dc(struct torture_context *torture)
{
	bool ret = true;
	NTSTATUS status;
	struct libnet_BecomeDC b;
	struct libnet_UnbecomeDC u;
	struct libnet_vampire_cb_state *s;
	struct ldb_message *msg;
	int ldb_ret;
	uint32_t i;
	char *private_dir;
	const char *address;
	struct nbt_name name;
	const char *netbios_name;
	struct cli_credentials *machine_account;
	struct test_join *tj;
	struct loadparm_context *lp_ctx;
	struct ldb_context *ldb;
	struct libnet_context *ctx;
	struct dsdb_schema *schema;

	char *location = NULL;
	torture_assert_ntstatus_ok(torture, torture_temp_dir(torture, "libnet_BecomeDC", &location), 
				   "torture_temp_dir should return NT_STATUS_OK" );

	netbios_name = lpcfg_parm_string(torture->lp_ctx, NULL, "become dc", "smbtorture dc");
	if (!netbios_name || !netbios_name[0]) {
		netbios_name = "smbtorturedc";
	}

	make_nbt_name_server(&name, torture_setting_string(torture, "host", NULL));

	/* do an initial name resolution to find its IP */
	status = resolve_name_ex(lpcfg_resolve_context(torture->lp_ctx),
				 0, 0,
				 &name, torture, &address, torture->ev);
	torture_assert_ntstatus_ok(torture, status, talloc_asprintf(torture,
				   "Failed to resolve %s - %s\n",
				   name.name, nt_errstr(status)));


	/* Join domain as a member server. */
	tj = torture_join_domain(torture, netbios_name,
				 ACB_WSTRUST,
				 &machine_account);
	torture_assert(torture, tj, talloc_asprintf(torture,
						    "%s failed to join domain as workstation\n",
						    netbios_name));

	s = libnet_vampire_cb_state_init(torture, torture->lp_ctx, torture->ev,
			       netbios_name,
			       torture_join_dom_netbios_name(tj),
			       torture_join_dom_dns_name(tj),
			       location);
	torture_assert(torture, s, "libnet_vampire_cb_state_init");

	ctx = libnet_context_init(torture->ev, torture->lp_ctx);
	ctx->cred = cmdline_credentials;

	ZERO_STRUCT(b);
	b.in.domain_dns_name		= torture_join_dom_dns_name(tj);
	b.in.domain_netbios_name	= torture_join_dom_netbios_name(tj);
	b.in.domain_sid			= torture_join_sid(tj);
	b.in.source_dsa_address		= address;
	b.in.dest_dsa_netbios_name	= netbios_name;

	b.in.callbacks.private_data	= s;
	b.in.callbacks.check_options	= libnet_vampire_cb_check_options;
	b.in.callbacks.prepare_db       = libnet_vampire_cb_prepare_db;
	b.in.callbacks.schema_chunk	= libnet_vampire_cb_schema_chunk;
	b.in.callbacks.config_chunk	= libnet_vampire_cb_store_chunk;
	b.in.callbacks.domain_chunk	= libnet_vampire_cb_store_chunk;

	status = libnet_BecomeDC(ctx, s, &b);
	torture_assert_ntstatus_ok_goto(torture, status, ret, cleanup, talloc_asprintf(torture,
				   "libnet_BecomeDC() failed - %s %s\n",
				   nt_errstr(status), b.out.error_string));
	ldb = libnet_vampire_cb_ldb(s);

	msg = ldb_msg_new(s);
	torture_assert_int_equal_goto(torture, (msg?1:0), 1, ret, cleanup,
				      "ldb_msg_new() failed\n");
	msg->dn = ldb_dn_new(msg, ldb, "@ROOTDSE");
	torture_assert_int_equal_goto(torture, (msg->dn?1:0), 1, ret, cleanup,
				      "ldb_msg_new(@ROOTDSE) failed\n");

	ldb_ret = ldb_msg_add_string(msg, "isSynchronized", "TRUE");
	torture_assert_int_equal_goto(torture, ldb_ret, LDB_SUCCESS, ret, cleanup,
				      "ldb_msg_add_string(msg, isSynchronized, TRUE) failed\n");

	for (i=0; i < msg->num_elements; i++) {
		msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
	}

	torture_comment(torture, "mark ROOTDSE with isSynchronized=TRUE\n");
	ldb_ret = ldb_modify(libnet_vampire_cb_ldb(s), msg);
	torture_assert_int_equal_goto(torture, ldb_ret, LDB_SUCCESS, ret, cleanup,
				      "ldb_modify() failed\n");
	
	/* commit the transaction now we know the secrets were written
	 * out properly
	*/
	ldb_ret = ldb_transaction_commit(ldb);
	torture_assert_int_equal_goto(torture, ldb_ret, LDB_SUCCESS, ret, cleanup,
				      "ldb_transaction_commit() failed\n");

	/* reopen the ldb */
	talloc_unlink(s, ldb);

	lp_ctx = libnet_vampire_cb_lp_ctx(s);
	private_dir = talloc_asprintf(s, "%s/%s", location, "private");
	lpcfg_set_cmdline(lp_ctx, "private dir", private_dir);
	torture_comment(torture, "Reopen the SAM LDB with system credentials and all replicated data: %s\n", private_dir);
	ldb = samdb_connect(s, torture->ev, lp_ctx, system_session(lp_ctx), 0);
	torture_assert_goto(torture, ldb != NULL, ret, cleanup,
				      talloc_asprintf(torture,
				      "Failed to open '%s/sam.ldb'\n", private_dir));

	torture_assert_goto(torture, dsdb_uses_global_schema(ldb), ret, cleanup,
						"Uses global schema");

	schema = dsdb_get_schema(ldb, s);
	torture_assert_goto(torture, schema != NULL, ret, cleanup,
				      "Failed to get loaded dsdb_schema\n");

	/* Make sure we get this from the command line */
	if (lpcfg_parm_bool(torture->lp_ctx, NULL, "become dc", "do not unjoin", false)) {
		talloc_free(s);
		return ret;
	}

cleanup:
	ZERO_STRUCT(u);
	u.in.domain_dns_name		= torture_join_dom_dns_name(tj);
	u.in.domain_netbios_name	= torture_join_dom_netbios_name(tj);
	u.in.source_dsa_address		= address;
	u.in.dest_dsa_netbios_name	= netbios_name;

	status = libnet_UnbecomeDC(ctx, s, &u);
	torture_assert_ntstatus_ok(torture, status, talloc_asprintf(torture,
				   "libnet_UnbecomeDC() failed - %s %s\n",
				   nt_errstr(status), u.out.error_string));

	/* Leave domain. */
	torture_leave_domain(torture, tj);

	talloc_free(s);
	return ret;
}
Beispiel #12
0
NTSTATUS connect_to_service(struct net_context *c,
					struct cli_state **cli_ctx,
					struct sockaddr_storage *server_ss,
					const char *server_name,
					const char *service_name,
					const char *service_type)
{
	NTSTATUS nt_status;
	int flags = 0;

	c->opt_password = net_prompt_pass(c, c->opt_user_name);

	if (c->opt_kerberos) {
		flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
	}

	if (c->opt_kerberos && c->opt_password) {
		flags |= CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS;
	}

	nt_status = cli_full_connection(cli_ctx, NULL, server_name,
					server_ss, c->opt_port,
					service_name, service_type,
					c->opt_user_name, c->opt_workgroup,
					c->opt_password, flags, Undefined, NULL);
	if (!NT_STATUS_IS_OK(nt_status)) {
		d_fprintf(stderr, "Could not connect to server %s\n", server_name);

		/* Display a nicer message depending on the result */

		if (NT_STATUS_V(nt_status) ==
		    NT_STATUS_V(NT_STATUS_LOGON_FAILURE))
			d_fprintf(stderr, "The username or password was not correct.\n");

		if (NT_STATUS_V(nt_status) ==
		    NT_STATUS_V(NT_STATUS_ACCOUNT_LOCKED_OUT))
			d_fprintf(stderr, "The account was locked out.\n");

		if (NT_STATUS_V(nt_status) ==
		    NT_STATUS_V(NT_STATUS_ACCOUNT_DISABLED))
			d_fprintf(stderr, "The account was disabled.\n");
		return nt_status;
	}

	if (c->smb_encrypt) {
		nt_status = cli_force_encryption(*cli_ctx,
					c->opt_user_name,
					c->opt_password,
					c->opt_workgroup);

		if (NT_STATUS_EQUAL(nt_status,NT_STATUS_NOT_SUPPORTED)) {
			d_printf("Encryption required and "
				"server that doesn't support "
				"UNIX extensions - failing connect\n");
		} else if (NT_STATUS_EQUAL(nt_status,NT_STATUS_UNKNOWN_REVISION)) {
			d_printf("Encryption required and "
				"can't get UNIX CIFS extensions "
				"version from server.\n");
		} else if (NT_STATUS_EQUAL(nt_status,NT_STATUS_UNSUPPORTED_COMPRESSION)) {
			d_printf("Encryption required and "
				"share %s doesn't support "
				"encryption.\n", service_name);
		} else if (!NT_STATUS_IS_OK(nt_status)) {
			d_printf("Encryption required and "
				"setup failed with error %s.\n",
				nt_errstr(nt_status));
		}

		if (!NT_STATUS_IS_OK(nt_status)) {
			cli_shutdown(*cli_ctx);
			*cli_ctx = NULL;
		}
	}

	return nt_status;
}
Beispiel #13
0
struct security_descriptor *svcctl_get_secdesc(TALLOC_CTX *mem_ctx,
					       struct messaging_context *msg_ctx,
					       const struct auth_session_info *session_info,
					       const char *name)
{
	struct dcerpc_binding_handle *h = NULL;
	uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
	struct policy_handle hive_hnd, key_hnd;
	struct security_descriptor *sd = NULL;
	char *key = NULL;
	NTSTATUS status;
	WERROR result = WERR_OK;

	key = talloc_asprintf(mem_ctx,
			      "%s\\%s\\Security",
			      TOP_LEVEL_SERVICES_KEY, name);
	if (key == NULL) {
		return NULL;
	}

	status = dcerpc_winreg_int_hklm_openkey(mem_ctx,
						session_info,
						msg_ctx,
						&h,
						key,
						false,
						access_mask,
						&hive_hnd,
						&key_hnd,
						&result);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(2, ("svcctl_set_secdesc: Could not open %s - %s\n",
			  key, nt_errstr(status)));
		return NULL;
	}
	if (!W_ERROR_IS_OK(result)) {
		DEBUG(2, ("svcctl_set_secdesc: Could not open %s - %s\n",
			  key, win_errstr(result)));
		return NULL;
	}

	status = dcerpc_winreg_query_sd(mem_ctx,
					h,
					&key_hnd,
					"Security",
					&sd,
					&result);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(2, ("svcctl_get_secdesc: error getting value 'Security': "
			  "%s\n", nt_errstr(status)));
		return NULL;
	}
	if (W_ERROR_EQUAL(result, WERR_FILE_NOT_FOUND)) {
		goto fallback_to_default_sd;
	} else if (!W_ERROR_IS_OK(result)) {
		DEBUG(2, ("svcctl_get_secdesc: error getting value 'Security': "
			  "%s\n", win_errstr(result)));
		return NULL;
	}

	goto done;

fallback_to_default_sd:
	DEBUG(6, ("svcctl_get_secdesc: constructing default secdesc for "
		  "service [%s]\n", name));
	sd = svcctl_gen_service_sd(mem_ctx);

done:
	return sd;
}
Beispiel #14
0
bool svcctl_set_secdesc(struct messaging_context *msg_ctx,
			const struct auth_session_info *session_info,
			const char *name,
			struct security_descriptor *sd)
{
	struct dcerpc_binding_handle *h = NULL;
	uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
	struct policy_handle hive_hnd;
	struct policy_handle key_hnd = { 0, };
	char *key = NULL;
	bool ok = false;
	TALLOC_CTX *tmp_ctx;
	NTSTATUS status;
	WERROR result = WERR_OK;

	tmp_ctx = talloc_stackframe();
	if (tmp_ctx == NULL) {
		return false;
	}

	key = talloc_asprintf(tmp_ctx, "%s\\%s", TOP_LEVEL_SERVICES_KEY, name);
	if (key == NULL) {
		goto done;
	}

	status = dcerpc_winreg_int_hklm_openkey(tmp_ctx,
						session_info,
						msg_ctx,
						&h,
						key,
						false,
						access_mask,
						&hive_hnd,
						&key_hnd,
						&result);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(0, ("svcctl_set_secdesc: Could not open %s - %s\n",
			  key, nt_errstr(status)));
		goto done;
	}
	if (!W_ERROR_IS_OK(result)) {
		DEBUG(0, ("svcctl_set_secdesc: Could not open %s - %s\n",
			  key, win_errstr(result)));
		goto done;
	}

	if (is_valid_policy_hnd(&key_hnd)) {
		dcerpc_winreg_CloseKey(h, tmp_ctx, &key_hnd, &result);
	}

	{
		enum winreg_CreateAction action = REG_ACTION_NONE;
		struct winreg_String wkey = { 0, };
		struct winreg_String wkeyclass;

		wkey.name = talloc_asprintf(tmp_ctx, "%s\\Security", key);
		if (wkey.name == NULL) {
			result = WERR_NOT_ENOUGH_MEMORY;
			goto done;
		}

		ZERO_STRUCT(wkeyclass);
		wkeyclass.name = "";

		status = dcerpc_winreg_CreateKey(h,
						 tmp_ctx,
						 &hive_hnd,
						 wkey,
						 wkeyclass,
						 0,
						 access_mask,
						 NULL,
						 &key_hnd,
						 &action,
						 &result);
		if (!NT_STATUS_IS_OK(status)) {
			DEBUG(2, ("svcctl_set_secdesc: Could not create key %s: %s\n",
				wkey.name, nt_errstr(status)));
			goto done;
		}
		if (!W_ERROR_IS_OK(result)) {
			DEBUG(2, ("svcctl_set_secdesc: Could not create key %s: %s\n",
				wkey.name, win_errstr(result)));
			goto done;
		}

		status = dcerpc_winreg_set_sd(tmp_ctx,
					      h,
					      &key_hnd,
					      "Security",
					      sd,
					      &result);
		if (!NT_STATUS_IS_OK(status)) {
			goto done;
		}
		if (!W_ERROR_IS_OK(result)) {
			goto done;
		}
	}

	ok = true;

done:
	if (is_valid_policy_hnd(&key_hnd)) {
		dcerpc_winreg_CloseKey(h, tmp_ctx, &key_hnd, &result);
	}

	talloc_free(tmp_ctx);
	return ok;
}
Beispiel #15
0
NTSTATUS remote_password_change(const char *remote_machine, const char *user_name, 
				const char *old_passwd, const char *new_passwd,
				char **err_str)
{
	struct nmb_name calling, called;
	struct cli_state *cli;
	struct rpc_pipe_client *pipe_hnd;
	struct sockaddr_storage ss;

	NTSTATUS result;
	bool pass_must_change = False;

	*err_str = NULL;

	if(!resolve_name( remote_machine, &ss, 0x20)) {
		asprintf(err_str, "Unable to find an IP address for machine "
			 "%s.\n", remote_machine);
		return NT_STATUS_UNSUCCESSFUL;
	}
 
	cli = cli_initialise();
	if (!cli) {
		return NT_STATUS_NO_MEMORY;
	}

	result = cli_connect(cli, remote_machine, &ss);
	if (!NT_STATUS_IS_OK(result)) {
		asprintf(err_str, "Unable to connect to SMB server on "
			 "machine %s. Error was : %s.\n",
			 remote_machine, nt_errstr(result));
		cli_shutdown(cli);
		return result;
	}
  
	make_nmb_name(&calling, global_myname() , 0x0);
	make_nmb_name(&called , remote_machine, 0x20);
	
	if (!cli_session_request(cli, &calling, &called)) {
		asprintf(err_str, "machine %s rejected the session setup. "
			 "Error was : %s.\n",
			 remote_machine, cli_errstr(cli) );
		result = cli_nt_error(cli);
		cli_shutdown(cli);
		return result;
	}
  
	cli->protocol = PROTOCOL_NT1;

	if (!cli_negprot(cli)) {
		asprintf(err_str, "machine %s rejected the negotiate "
			 "protocol. Error was : %s.\n",        
			 remote_machine, cli_errstr(cli) );
		result = cli_nt_error(cli);
		cli_shutdown(cli);
		return result;
	}
  
	/* Given things like SMB signing, restrict anonymous and the like, 
	   try an authenticated connection first */
	result = cli_session_setup(cli, user_name,
				   old_passwd, strlen(old_passwd)+1,
				   old_passwd, strlen(old_passwd)+1, "");

	if (!NT_STATUS_IS_OK(result)) {

		/* Password must change or Password expired are the only valid
		 * error conditions here from where we can proceed, the rest like
		 * account locked out or logon failure will lead to errors later
		 * anyway */

		if (!NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_MUST_CHANGE) &&
		    !NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_EXPIRED)) {
			asprintf(err_str, "Could not connect to machine %s: "
				 "%s\n", remote_machine, cli_errstr(cli));
			cli_shutdown(cli);
			return result;
		}

		pass_must_change = True;

		/*
		 * We should connect as the anonymous user here, in case
		 * the server has "must change password" checked...
		 * Thanks to <*****@*****.**> for this fix.
		 */

		result = cli_session_setup(cli, "", "", 0, "", 0, "");

		if (!NT_STATUS_IS_OK(result)) {
			asprintf(err_str, "machine %s rejected the session "
				 "setup. Error was : %s.\n",        
				 remote_machine, cli_errstr(cli) );
			cli_shutdown(cli);
			return result;
		}

		cli_init_creds(cli, "", "", NULL);
	} else {
		cli_init_creds(cli, user_name, "", old_passwd);
	}

	if (!cli_send_tconX(cli, "IPC$", "IPC", "", 1)) {
		asprintf(err_str, "machine %s rejected the tconX on the IPC$ "
			 "share. Error was : %s.\n",
			 remote_machine, cli_errstr(cli) );
		result = cli_nt_error(cli);
		cli_shutdown(cli);
		return result;
	}

	/* Try not to give the password away too easily */

	if (!pass_must_change) {
		pipe_hnd = cli_rpc_pipe_open_ntlmssp(cli,
						PI_SAMR,
						PIPE_AUTH_LEVEL_PRIVACY,
						"", /* what domain... ? */
						user_name,
						old_passwd,
						&result);
	} else {
		/*
		 * If the user password must be changed the ntlmssp bind will
		 * fail the same way as the session setup above did. The
		 * difference ist that with a pipe bind we don't get a good
		 * error message, the result will be that the rpc call below
		 * will just fail. So we do it anonymously, there's no other
		 * way.
		 */
		pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &result);
	}

	if (!pipe_hnd) {
		if (lp_client_lanman_auth()) {
			/* Use the old RAP method. */
			if (!cli_oem_change_password(cli, user_name, new_passwd, old_passwd)) {
				asprintf(err_str, "machine %s rejected the "
					 "password change: Error was : %s.\n",
					 remote_machine, cli_errstr(cli) );
				result = cli_nt_error(cli);
				cli_shutdown(cli);
				return result;
			}
		} else {
			asprintf(err_str, "SAMR connection to machine %s "
				 "failed. Error was %s, but LANMAN password "
				 "changed are disabled\n",
				 nt_errstr(result), remote_machine);
			result = cli_nt_error(cli);
			cli_shutdown(cli);
			return result;
		}
	}

	if (NT_STATUS_IS_OK(result = rpccli_samr_chgpasswd_user(pipe_hnd, pipe_hnd->mem_ctx, user_name, 
							     new_passwd, old_passwd))) {
		/* Great - it all worked! */
		cli_shutdown(cli);
		return NT_STATUS_OK;

	} else if (!(NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) 
		     || NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))) {
		/* it failed, but for reasons such as wrong password, too short etc ... */
		
		asprintf(err_str, "machine %s rejected the password change: "
			 "Error was : %s.\n",
			 remote_machine, get_friendly_nt_error_msg(result));
		cli_shutdown(cli);
		return result;
	}

	/* OK, that failed, so try again... */
	cli_rpc_pipe_close(pipe_hnd);
	
	/* Try anonymous NTLMSSP... */
	cli_init_creds(cli, "", "", NULL);
	
	result = NT_STATUS_UNSUCCESSFUL;
	
	/* OK, this is ugly, but... try an anonymous pipe. */
	pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &result);

	if ( pipe_hnd &&
		(NT_STATUS_IS_OK(result = rpccli_samr_chgpasswd_user(pipe_hnd,
						pipe_hnd->mem_ctx,
						user_name, 
						new_passwd,
						old_passwd)))) {
		/* Great - it all worked! */
		cli_shutdown(cli);
		return NT_STATUS_OK;
	} else {
		if (!(NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) 
		      || NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))) {
			/* it failed, but again it was due to things like new password too short */

			asprintf(err_str, "machine %s rejected the "
				 "(anonymous) password change: Error was : "
				 "%s.\n", remote_machine,
				 get_friendly_nt_error_msg(result));
			cli_shutdown(cli);
			return result;
		}
		
		/* We have failed to change the user's password, and we think the server
		   just might not support SAMR password changes, so fall back */
		
		if (lp_client_lanman_auth()) {
			/* Use the old RAP method. */
			if (cli_oem_change_password(cli, user_name, new_passwd, old_passwd)) {
				/* SAMR failed, but the old LanMan protocol worked! */

				cli_shutdown(cli);
				return NT_STATUS_OK;
			}
			asprintf(err_str, "machine %s rejected the password "
				 "change: Error was : %s.\n",
				 remote_machine, cli_errstr(cli) );
			result = cli_nt_error(cli);
			cli_shutdown(cli);
			return result;
		} else {
			asprintf(err_str, "SAMR connection to machine %s "
				 "failed. Error was %s, but LANMAN password "
				 "changed are disabled\n",
				nt_errstr(result), remote_machine);
			cli_shutdown(cli);
			return NT_STATUS_UNSUCCESSFUL;
		}
	}
}
Beispiel #16
0
static bool api_pipe_bind_req(struct pipes_struct *p,
				struct ncacn_packet *pkt)
{
	struct dcerpc_auth auth_info;
	uint16 assoc_gid;
	unsigned int auth_type = DCERPC_AUTH_TYPE_NONE;
	NTSTATUS status;
	struct ndr_syntax_id id;
	uint8_t pfc_flags = 0;
	union dcerpc_payload u;
	struct dcerpc_ack_ctx bind_ack_ctx;
	DATA_BLOB auth_resp = data_blob_null;
	DATA_BLOB auth_blob = data_blob_null;
	const struct ndr_interface_table *table;

	/* No rebinds on a bound pipe - use alter context. */
	if (p->pipe_bound) {
		DEBUG(2,("Rejecting bind request on bound rpc connection\n"));
		return setup_bind_nak(p, pkt);
	}

	if (pkt->u.bind.num_contexts == 0) {
		DEBUG(0, ("api_pipe_bind_req: no rpc contexts around\n"));
		goto err_exit;
	}

	/*
	 * Try and find the correct pipe name to ensure
	 * that this is a pipe name we support.
	 */
	id = pkt->u.bind.ctx_list[0].abstract_syntax;

	table = ndr_table_by_uuid(&id.uuid);
	if (table == NULL) {
		DEBUG(0,("unknown interface\n"));
		return false;
	}

	if (rpc_srv_pipe_exists_by_id(&id)) {
		DEBUG(3, ("api_pipe_bind_req: %s -> %s rpc service\n",
			  rpc_srv_get_pipe_cli_name(&id),
			  rpc_srv_get_pipe_srv_name(&id)));
	} else {
		status = smb_probe_module(
			"rpc", dcerpc_default_transport_endpoint(pkt,
				NCACN_NP, table));

		if (NT_STATUS_IS_ERR(status)) {
			DEBUG(3,("api_pipe_bind_req: Unknown rpc service name "
                                 "%s in bind request.\n",
				 ndr_interface_name(&id.uuid,
						    id.if_version)));

			return setup_bind_nak(p, pkt);
		}

		if (rpc_srv_get_pipe_interface_by_cli_name(
				dcerpc_default_transport_endpoint(pkt,
					NCACN_NP, table),
				&id)) {
			DEBUG(3, ("api_pipe_bind_req: %s -> %s rpc service\n",
				  rpc_srv_get_pipe_cli_name(&id),
				  rpc_srv_get_pipe_srv_name(&id)));
		} else {
			DEBUG(0, ("module %s doesn't provide functions for "
				  "pipe %s!\n",
				  ndr_interface_name(&id.uuid,
						     id.if_version),
				  ndr_interface_name(&id.uuid,
						     id.if_version)));
			return setup_bind_nak(p, pkt);
		}
	}

	DEBUG(5,("api_pipe_bind_req: make response. %d\n", __LINE__));

	if (pkt->u.bind.assoc_group_id != 0) {
		assoc_gid = pkt->u.bind.assoc_group_id;
	} else {
		assoc_gid = 0x53f0;
	}

	/*
	 * Create the bind response struct.
	 */

	/* If the requested abstract synt uuid doesn't match our client pipe,
		reject the bind_ack & set the transfer interface synt to all 0's,
		ver 0 (observed when NT5 attempts to bind to abstract interfaces
		unknown to NT4)
		Needed when adding entries to a DACL from NT5 - SK */

	if (check_bind_req(p,
			&pkt->u.bind.ctx_list[0].abstract_syntax,
			&pkt->u.bind.ctx_list[0].transfer_syntaxes[0],
			pkt->u.bind.ctx_list[0].context_id)) {

		bind_ack_ctx.result = 0;
		bind_ack_ctx.reason.value = 0;
		bind_ack_ctx.syntax = pkt->u.bind.ctx_list[0].transfer_syntaxes[0];
	} else {
		p->pipe_bound = False;
		/* Rejection reason: abstract syntax not supported */
		bind_ack_ctx.result = DCERPC_BIND_PROVIDER_REJECT;
		bind_ack_ctx.reason.value = DCERPC_BIND_REASON_ASYNTAX;
		bind_ack_ctx.syntax = ndr_syntax_id_null;
	}

	/*
	 * Check if this is an authenticated bind request.
	 */
	if (pkt->auth_length) {
		/* Quick length check. Won't catch a bad auth footer,
		 * prevents overrun. */

		if (pkt->frag_length < RPC_HEADER_LEN +
					DCERPC_AUTH_TRAILER_LENGTH +
					pkt->auth_length) {
			DEBUG(0,("api_pipe_bind_req: auth_len (%u) "
				"too long for fragment %u.\n",
				(unsigned int)pkt->auth_length,
				(unsigned int)pkt->frag_length));
			goto err_exit;
		}

		/*
		 * Decode the authentication verifier.
		 */
		status = dcerpc_pull_dcerpc_auth(pkt,
						 &pkt->u.bind.auth_info,
						 &auth_info, p->endian);
		if (!NT_STATUS_IS_OK(status)) {
			DEBUG(0, ("Unable to unmarshall dcerpc_auth.\n"));
			goto err_exit;
		}

		auth_type = auth_info.auth_type;

		/* Work out if we have to sign or seal etc. */
		switch (auth_info.auth_level) {
		case DCERPC_AUTH_LEVEL_INTEGRITY:
			p->auth.auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
			break;
		case DCERPC_AUTH_LEVEL_PRIVACY:
			p->auth.auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
			break;
		case DCERPC_AUTH_LEVEL_CONNECT:
			p->auth.auth_level = DCERPC_AUTH_LEVEL_CONNECT;
			break;
		default:
			DEBUG(0, ("Unexpected auth level (%u).\n",
				(unsigned int)auth_info.auth_level ));
			goto err_exit;
		}

		switch (auth_type) {
		case DCERPC_AUTH_TYPE_NTLMSSP:
			if (!pipe_auth_generic_bind(p, pkt,
						    &auth_info, &auth_resp)) {
				goto err_exit;
			}
			assoc_gid = 0x7a77;
			break;

		case DCERPC_AUTH_TYPE_SCHANNEL:
			if (!pipe_auth_generic_bind(p, pkt,
						    &auth_info, &auth_resp)) {
				goto err_exit;
			}
			if (!session_info_set_session_key(p->session_info, generic_session_key())) {
				DEBUG(0, ("session_info_set_session_key failed\n"));
				goto err_exit;
			}
			p->pipe_bound = true;
			break;

		case DCERPC_AUTH_TYPE_SPNEGO:
		case DCERPC_AUTH_TYPE_KRB5:
			if (!pipe_auth_generic_bind(p, pkt,
						    &auth_info, &auth_resp)) {
				goto err_exit;
			}
			break;

		case DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM:
			if (p->transport == NCALRPC && p->ncalrpc_as_system) {
				TALLOC_FREE(p->session_info);

				status = make_session_info_system(p,
								  &p->session_info);
				if (!NT_STATUS_IS_OK(status)) {
					goto err_exit;
				}

				auth_resp = data_blob_talloc(pkt,
							     "NCALRPC_AUTH_OK",
							     15);

				p->auth.auth_type = DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM;
				p->pipe_bound = true;
			} else {
				goto err_exit;
			}
			break;

		case DCERPC_AUTH_TYPE_NONE:
			break;

		default:
			DEBUG(0, ("Unknown auth type %x requested.\n", auth_type));
			goto err_exit;
		}
	}

	if (auth_type == DCERPC_AUTH_TYPE_NONE) {
		/* Unauthenticated bind request. */
		/* We're finished - no more packets. */
		p->auth.auth_type = DCERPC_AUTH_TYPE_NONE;
		/* We must set the pipe auth_level here also. */
		p->auth.auth_level = DCERPC_AUTH_LEVEL_NONE;
		p->pipe_bound = True;
		/* The session key was initialized from the SMB
		 * session in make_internal_rpc_pipe_p */
	}

	ZERO_STRUCT(u.bind_ack);
	u.bind_ack.max_xmit_frag = RPC_MAX_PDU_FRAG_LEN;
	u.bind_ack.max_recv_frag = RPC_MAX_PDU_FRAG_LEN;
	u.bind_ack.assoc_group_id = assoc_gid;

	/* name has to be \PIPE\xxxxx */
	u.bind_ack.secondary_address =
			talloc_asprintf(pkt, "\\PIPE\\%s",
					rpc_srv_get_pipe_srv_name(&id));
	if (!u.bind_ack.secondary_address) {
		DEBUG(0, ("Out of memory!\n"));
		goto err_exit;
	}
	u.bind_ack.secondary_address_size =
				strlen(u.bind_ack.secondary_address) + 1;

	u.bind_ack.num_results = 1;
	u.bind_ack.ctx_list = &bind_ack_ctx;

	/* NOTE: We leave the auth_info empty so we can calculate the padding
	 * later and then append the auth_info --simo */

	/*
	 * Marshall directly into the outgoing PDU space. We
	 * must do this as we need to set to the bind response
	 * header and are never sending more than one PDU here.
	 */

	pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;

	if (p->auth.hdr_signing) {
		pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
	}

	status = dcerpc_push_ncacn_packet(p->mem_ctx,
					  DCERPC_PKT_BIND_ACK,
					  pfc_flags,
					  auth_resp.length,
					  pkt->call_id,
					  &u,
					  &p->out_data.frag);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(0, ("Failed to marshall bind_ack packet. (%s)\n",
			  nt_errstr(status)));
	}

	if (auth_resp.length) {

		status = dcerpc_push_dcerpc_auth(pkt,
						 auth_type,
						 auth_info.auth_level,
						 0,
						 1, /* auth_context_id */
						 &auth_resp,
						 &auth_blob);
		if (!NT_STATUS_IS_OK(status)) {
			DEBUG(0, ("Marshalling of dcerpc_auth failed.\n"));
			goto err_exit;
		}
	}

	/* Now that we have the auth len store it into the right place in
	 * the dcerpc header */
	dcerpc_set_frag_length(&p->out_data.frag,
				p->out_data.frag.length + auth_blob.length);

	if (auth_blob.length) {

		if (!data_blob_append(p->mem_ctx, &p->out_data.frag,
					auth_blob.data, auth_blob.length)) {
			DEBUG(0, ("Append of auth info failed.\n"));
			goto err_exit;
		}
	}

	/*
	 * Setup the lengths for the initial reply.
	 */

	p->out_data.data_sent_length = 0;
	p->out_data.current_pdu_sent = 0;

	TALLOC_FREE(auth_blob.data);
	return True;

  err_exit:

	data_blob_free(&p->out_data.frag);
	TALLOC_FREE(auth_blob.data);
	return setup_bind_nak(p, pkt);
}
Beispiel #17
0
/*****************************************************************************
 For idmap conversion: convert one record to new format
 Ancient versions (eg 2.2.3a) of winbindd_idmap.tdb mapped DOMAINNAME/rid
 instead of the SID.
*****************************************************************************/
static int convert_fn(struct db_record *rec, void *private_data)
{
	struct winbindd_domain *domain;
	char *p;
	NTSTATUS status;
	struct dom_sid sid;
	uint32 rid;
	fstring keystr;
	fstring dom_name;
	TDB_DATA key2;
	struct convert_fn_state *s = (struct convert_fn_state *)private_data;

	DEBUG(10,("Converting %s\n", (const char *)rec->key.dptr));

	p = strchr((const char *)rec->key.dptr, '/');
	if (!p)
		return 0;

	*p = 0;
	fstrcpy(dom_name, (const char *)rec->key.dptr);
	*p++ = '/';

	domain = find_domain_from_name(dom_name);
	if (domain == NULL) {
		/* We must delete the old record. */
		DEBUG(0,("Unable to find domain %s\n", dom_name ));
		DEBUG(0,("deleting record %s\n", (const char *)rec->key.dptr ));

		status = rec->delete_rec(rec);
		if (!NT_STATUS_IS_OK(status)) {
			DEBUG(0, ("Unable to delete record %s:%s\n",
				(const char *)rec->key.dptr,
				nt_errstr(status)));
			s->failed = true;
			return -1;
		}

		return 0;
	}

	rid = atoi(p);

	sid_compose(&sid, &domain->sid, rid);

	sid_to_fstring(keystr, &sid);
	key2 = string_term_tdb_data(keystr);

	status = dbwrap_store(s->db, key2, rec->value, TDB_INSERT);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(0,("Unable to add record %s:%s\n",
			(const char *)key2.dptr,
			nt_errstr(status)));
		s->failed = true;
		return -1;
	}

	status = dbwrap_store(s->db, rec->value, key2, TDB_REPLACE);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(0,("Unable to update record %s:%s\n",
			(const char *)rec->value.dptr,
			nt_errstr(status)));
		s->failed = true;
		return -1;
	}

	status = rec->delete_rec(rec);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(0,("Unable to delete record %s:%s\n",
			(const char *)rec->key.dptr,
			nt_errstr(status)));
		s->failed = true;
		return -1;
	}

	return 0;
}
Beispiel #18
0
bool api_pipe_bind_auth3(struct pipes_struct *p, struct ncacn_packet *pkt)
{
	struct dcerpc_auth auth_info;
	DATA_BLOB response = data_blob_null;
	struct gensec_security *gensec_security;
	NTSTATUS status;

	DEBUG(5, ("api_pipe_bind_auth3: decode request. %d\n", __LINE__));

	if (pkt->auth_length == 0) {
		DEBUG(1, ("No auth field sent for bind request!\n"));
		goto err;
	}

	/* Ensure there's enough data for an authenticated request. */
	if (pkt->frag_length < RPC_HEADER_LEN
				+ DCERPC_AUTH_TRAILER_LENGTH
				+ pkt->auth_length) {
			DEBUG(1,("api_pipe_ntlmssp_auth_process: auth_len "
				"%u is too large.\n",
                        (unsigned int)pkt->auth_length));
		goto err;
	}

	/*
	 * Decode the authentication verifier response.
	 */

	status = dcerpc_pull_dcerpc_auth(pkt,
					 &pkt->u.auth3.auth_info,
					 &auth_info, p->endian);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1, ("Failed to unmarshall dcerpc_auth.\n"));
		goto err;
	}

	/* We must NEVER look at auth_info->auth_pad_len here,
	 * as old Samba client code gets it wrong and sends it
	 * as zero. JRA.
	 */

	if (auth_info.auth_type != p->auth.auth_type) {
		DEBUG(1, ("Auth type mismatch! Client sent %d, "
			  "but auth was started as type %d!\n",
			  auth_info.auth_type, p->auth.auth_type));
		goto err;
	}

	switch (auth_info.auth_type) {
	case DCERPC_AUTH_TYPE_NTLMSSP:
	case DCERPC_AUTH_TYPE_KRB5:
	case DCERPC_AUTH_TYPE_SPNEGO:
		gensec_security = talloc_get_type_abort(p->auth.auth_ctx,
						    struct gensec_security);
		status = auth_generic_server_step(gensec_security,
					     pkt, &auth_info.credentials,
					     &response);
		break;
	default:
		DEBUG(1, (__location__ ": incorrect auth type (%u).\n",
			  (unsigned int)auth_info.auth_type));
		return false;
	}

	if (NT_STATUS_EQUAL(status,
			    NT_STATUS_MORE_PROCESSING_REQUIRED) ||
	    response.length) {
		DEBUG(1, (__location__ ": This was supposed to be the final "
			  "leg, but crypto machinery claims a response is "
			  "needed, aborting auth!\n"));
		data_blob_free(&response);
		goto err;
	}
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(2, ("Auth failed (%s)\n", nt_errstr(status)));
		goto err;
	}

	/* Now verify auth was indeed successful and extract server info */
	status = pipe_auth_verify_final(p);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(2, ("Auth Verify failed (%s)\n", nt_errstr(status)));
		goto err;
	}

	return true;

err:

	TALLOC_FREE(p->auth.auth_ctx);
	return false;
}
Beispiel #19
0
static NTSTATUS get_nt_acl_internal(vfs_handle_struct *handle,
				files_struct *fsp,
				const char *name,
			        uint32_t security_info,
				struct security_descriptor **ppdesc)
{
	DATA_BLOB blob = data_blob_null;
	NTSTATUS status;
	uint16_t hash_type = XATTR_SD_HASH_TYPE_NONE;
	uint8_t hash[XATTR_SD_HASH_SIZE];
	uint8_t hash_tmp[XATTR_SD_HASH_SIZE];
	struct security_descriptor *psd = NULL;
	struct security_descriptor *pdesc_next = NULL;
	bool ignore_file_system_acl = lp_parm_bool(SNUM(handle->conn),
						ACL_MODULE_NAME,
						"ignore system acls",
						false);

	if (fsp && name == NULL) {
		name = fsp->fsp_name->base_name;
	}

	DEBUG(10, ("get_nt_acl_internal: name=%s\n", name));

	/* Get the full underlying sd for the hash
	   or to return as backup. */
	if (fsp) {
		status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
				fsp,
				HASH_SECURITY_INFO,
				&pdesc_next);
	} else {
		status = SMB_VFS_NEXT_GET_NT_ACL(handle,
				name,
				HASH_SECURITY_INFO,
				&pdesc_next);
	}

	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(10, ("get_nt_acl_internal: get_next_acl for file %s "
			"returned %s\n",
			name,
			nt_errstr(status)));
		return status;
	}

	status = get_acl_blob(talloc_tos(), handle, fsp, name, &blob);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(10, ("get_nt_acl_internal: get_acl_blob returned %s\n",
			nt_errstr(status)));
		psd = pdesc_next;
		goto out;
	}

	status = parse_acl_blob(&blob, &psd,
				&hash_type, &hash[0]);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(10, ("parse_acl_blob returned %s\n",
				nt_errstr(status)));
		psd = pdesc_next;
		goto out;
	}

	/* Ensure the hash type is one we know. */
	switch (hash_type) {
		case XATTR_SD_HASH_TYPE_NONE:
			/* No hash, just return blob sd. */
			goto out;
		case XATTR_SD_HASH_TYPE_SHA256:
			break;
		default:
			DEBUG(10, ("get_nt_acl_internal: ACL blob revision "
				"mismatch (%u) for file %s\n",
				(unsigned int)hash_type,
				name));
			TALLOC_FREE(psd);
			psd = pdesc_next;
			goto out;
	}

	if (ignore_file_system_acl) {
		goto out;
	}

	status = hash_sd_sha256(pdesc_next, hash_tmp);
	if (!NT_STATUS_IS_OK(status)) {
		TALLOC_FREE(psd);
		psd = pdesc_next;
		goto out;
	}

	if (memcmp(&hash[0], &hash_tmp[0], XATTR_SD_HASH_SIZE) == 0) {
		/* Hash matches, return blob sd. */
		DEBUG(10, ("get_nt_acl_internal: blob hash "
			"matches for file %s\n",
			name ));
		goto out;
	}

	/* Hash doesn't match, return underlying sd. */
	TALLOC_FREE(psd);
	psd = pdesc_next;

  out:

	if (psd != pdesc_next) {
		/* We're returning the blob, throw
 		 * away the filesystem SD. */
		TALLOC_FREE(pdesc_next);
	} else {
		SMB_STRUCT_STAT sbuf;
		SMB_STRUCT_STAT *psbuf = &sbuf;
		bool is_directory = false;
		/*
		 * We're returning the underlying ACL from the
		 * filesystem. If it's a directory, and has no
		 * inheritable ACE entries we have to fake them.
		 */
		if (fsp) {
			status = vfs_stat_fsp(fsp);
			if (!NT_STATUS_IS_OK(status)) {
				return status;
			}
			psbuf = &fsp->fsp_name->st;
		} else {
			int ret = vfs_stat_smb_fname(handle->conn,
						name,
						&sbuf);
			if (ret == -1) {
				return map_nt_error_from_unix(errno);
			}
		}
		is_directory = S_ISDIR(psbuf->st_ex_mode);

		if (ignore_file_system_acl) {
			TALLOC_FREE(pdesc_next);
			status = make_default_filesystem_acl(talloc_tos(),
						name,
						psbuf,
						&psd);
			if (!NT_STATUS_IS_OK(status)) {
				return status;
			}
		} else {
			if (is_directory &&
				!sd_has_inheritable_components(psd,
							true)) {
				add_directory_inheritable_components(handle,
							name,
							psbuf,
							psd);
			}
			/* The underlying POSIX module always sets
			   the ~SEC_DESC_DACL_PROTECTED bit, as ACLs
			   can't be inherited in this way under POSIX.
			   Remove it for Windows-style ACLs. */
			psd->type &= ~SEC_DESC_DACL_PROTECTED;
		}
	}

	if (!(security_info & SECINFO_OWNER)) {
		psd->owner_sid = NULL;
	}
	if (!(security_info & SECINFO_GROUP)) {
		psd->group_sid = NULL;
	}
	if (!(security_info & SECINFO_DACL)) {
		psd->type &= ~SEC_DESC_DACL_PRESENT;
		psd->dacl = NULL;
	}
	if (!(security_info & SECINFO_SACL)) {
		psd->type &= ~SEC_DESC_SACL_PRESENT;
		psd->sacl = NULL;
	}

	TALLOC_FREE(blob.data);
	*ppdesc = psd;

	if (DEBUGLEVEL >= 10) {
		DEBUG(10,("get_nt_acl_internal: returning acl for %s is:\n",
			name ));
		NDR_PRINT_DEBUG(security_descriptor, psd);
	}

	return NT_STATUS_OK;
}
Beispiel #20
0
static bool api_pipe_alter_context(struct pipes_struct *p,
					struct ncacn_packet *pkt)
{
	struct dcerpc_auth auth_info;
	uint16 assoc_gid;
	NTSTATUS status;
	union dcerpc_payload u;
	struct dcerpc_ack_ctx bind_ack_ctx;
	DATA_BLOB auth_resp = data_blob_null;
	DATA_BLOB auth_blob = data_blob_null;
	int pad_len = 0;
	struct gensec_security *gensec_security;

	DEBUG(5,("api_pipe_alter_context: make response. %d\n", __LINE__));

	if (pkt->u.bind.assoc_group_id != 0) {
		assoc_gid = pkt->u.bind.assoc_group_id;
	} else {
		assoc_gid = 0x53f0;
	}

	/*
	 * Create the bind response struct.
	 */

	/* If the requested abstract synt uuid doesn't match our client pipe,
		reject the bind_ack & set the transfer interface synt to all 0's,
		ver 0 (observed when NT5 attempts to bind to abstract interfaces
		unknown to NT4)
		Needed when adding entries to a DACL from NT5 - SK */

	if (check_bind_req(p,
			&pkt->u.bind.ctx_list[0].abstract_syntax,
			&pkt->u.bind.ctx_list[0].transfer_syntaxes[0],
			pkt->u.bind.ctx_list[0].context_id)) {

		bind_ack_ctx.result = 0;
		bind_ack_ctx.reason.value = 0;
		bind_ack_ctx.syntax = pkt->u.bind.ctx_list[0].transfer_syntaxes[0];
	} else {
		p->pipe_bound = False;
		/* Rejection reason: abstract syntax not supported */
		bind_ack_ctx.result = DCERPC_BIND_PROVIDER_REJECT;
		bind_ack_ctx.reason.value = DCERPC_BIND_REASON_ASYNTAX;
		bind_ack_ctx.syntax = ndr_syntax_id_null;
	}

	/*
	 * Check if this is an authenticated alter context request.
	 */
	if (pkt->auth_length) {
		/* Quick length check. Won't catch a bad auth footer,
		 * prevents overrun. */

		if (pkt->frag_length < RPC_HEADER_LEN +
					DCERPC_AUTH_TRAILER_LENGTH +
					pkt->auth_length) {
			DEBUG(0,("api_pipe_alter_context: auth_len (%u) "
				"too long for fragment %u.\n",
				(unsigned int)pkt->auth_length,
				(unsigned int)pkt->frag_length ));
			goto err_exit;
		}

		status = dcerpc_pull_dcerpc_auth(pkt,
						 &pkt->u.bind.auth_info,
						 &auth_info, p->endian);
		if (!NT_STATUS_IS_OK(status)) {
			DEBUG(0, ("Unable to unmarshall dcerpc_auth.\n"));
			goto err_exit;
		}

		/* We can only finish if the pipe is unbound for now */
		if (p->pipe_bound) {
			DEBUG(0, (__location__ ": Pipe already bound, "
				  "Altering Context not yet supported!\n"));
			goto err_exit;
		}

		if (auth_info.auth_type != p->auth.auth_type) {
			DEBUG(0, ("Auth type mismatch! Client sent %d, "
				  "but auth was started as type %d!\n",
				  auth_info.auth_type, p->auth.auth_type));
			goto err_exit;
		}


		switch (auth_info.auth_type) {
		case DCERPC_AUTH_TYPE_SPNEGO:
		case DCERPC_AUTH_TYPE_KRB5:
		case DCERPC_AUTH_TYPE_NTLMSSP:
			gensec_security = talloc_get_type_abort(p->auth.auth_ctx,
						    struct gensec_security);
			status = auth_generic_server_step(gensec_security,
						     pkt,
						     &auth_info.credentials,
						     &auth_resp);
			break;

		default:
			DEBUG(3, (__location__ ": Usupported auth type (%d) "
				  "in alter-context call\n",
				  auth_info.auth_type));
			goto err_exit;
		}

		if (NT_STATUS_IS_OK(status)) {
			/* third leg of auth, verify auth info */
			status = pipe_auth_verify_final(p);
			if (!NT_STATUS_IS_OK(status)) {
				DEBUG(0, ("Auth Verify failed (%s)\n",
					  nt_errstr(status)));
				goto err_exit;
			}
		} else if (NT_STATUS_EQUAL(status,
					NT_STATUS_MORE_PROCESSING_REQUIRED)) {
			DEBUG(10, ("More auth legs required.\n"));
		} else {
			DEBUG(0, ("Auth step returned an error (%s)\n",
				  nt_errstr(status)));
			goto err_exit;
		}
	}

	ZERO_STRUCT(u.alter_resp);
	u.alter_resp.max_xmit_frag = RPC_MAX_PDU_FRAG_LEN;
	u.alter_resp.max_recv_frag = RPC_MAX_PDU_FRAG_LEN;
	u.alter_resp.assoc_group_id = assoc_gid;

	/* secondary address CAN be NULL
	 * as the specs say it's ignored.
	 * It MUST be NULL to have the spoolss working.
	 */
	u.alter_resp.secondary_address = "";
	u.alter_resp.secondary_address_size = 1;

	u.alter_resp.num_results = 1;
	u.alter_resp.ctx_list = &bind_ack_ctx;

	/* NOTE: We leave the auth_info empty so we can calculate the padding
	 * later and then append the auth_info --simo */

	/*
	 * Marshall directly into the outgoing PDU space. We
	 * must do this as we need to set to the bind response
	 * header and are never sending more than one PDU here.
	 */

	status = dcerpc_push_ncacn_packet(p->mem_ctx,
					  DCERPC_PKT_ALTER_RESP,
					  DCERPC_PFC_FLAG_FIRST |
						DCERPC_PFC_FLAG_LAST,
					  auth_resp.length,
					  pkt->call_id,
					  &u,
					  &p->out_data.frag);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(0, ("Failed to marshall bind_ack packet. (%s)\n",
			  nt_errstr(status)));
	}

	if (auth_resp.length) {

		/* Work out any padding needed before the auth footer. */
		pad_len = p->out_data.frag.length % SERVER_NDR_PADDING_SIZE;
		if (pad_len) {
			pad_len = SERVER_NDR_PADDING_SIZE - pad_len;
			DEBUG(10, ("auth pad_len = %u\n",
				   (unsigned int)pad_len));
		}

		status = dcerpc_push_dcerpc_auth(pkt,
						 auth_info.auth_type,
						 auth_info.auth_level,
						 pad_len,
						 1, /* auth_context_id */
						 &auth_resp,
						 &auth_blob);
		if (!NT_STATUS_IS_OK(status)) {
			DEBUG(0, ("Marshalling of dcerpc_auth failed.\n"));
			goto err_exit;
		}
	}

	/* Now that we have the auth len store it into the right place in
	 * the dcerpc header */
	dcerpc_set_frag_length(&p->out_data.frag,
				p->out_data.frag.length +
					pad_len + auth_blob.length);

	if (auth_resp.length) {
		if (pad_len) {
			char pad[SERVER_NDR_PADDING_SIZE];
			memset(pad, '\0', SERVER_NDR_PADDING_SIZE);
			if (!data_blob_append(p->mem_ctx,
						&p->out_data.frag,
						pad, pad_len)) {
				DEBUG(0, ("api_pipe_bind_req: failed to add "
					  "%u bytes of pad data.\n",
					  (unsigned int)pad_len));
				goto err_exit;
			}
		}

		if (!data_blob_append(p->mem_ctx, &p->out_data.frag,
					auth_blob.data, auth_blob.length)) {
			DEBUG(0, ("Append of auth info failed.\n"));
			goto err_exit;
		}
	}

	/*
	 * Setup the lengths for the initial reply.
	 */

	p->out_data.data_sent_length = 0;
	p->out_data.current_pdu_sent = 0;

	TALLOC_FREE(auth_blob.data);
	return True;

  err_exit:

	data_blob_free(&p->out_data.frag);
	TALLOC_FREE(auth_blob.data);
	return setup_bind_nak(p, pkt);
}
Beispiel #21
0
bool torture_domain_close_samr(struct torture_context *torture)
{
	bool ret = true;
	NTSTATUS status;
	TALLOC_CTX *mem_ctx = NULL;
	struct libnet_context *ctx;
	struct lsa_String domain_name;
	struct dcerpc_binding *binding;
	uint32_t access_mask;
	struct policy_handle h;
	struct dcerpc_pipe *p;
	struct libnet_DomainClose r;
	struct dom_sid *sid;

	status = torture_rpc_binding(torture, &binding);
	if (!NT_STATUS_IS_OK(status)) {
		return false;
	}

	ctx = libnet_context_init(torture->ev, torture->lp_ctx);
	if (ctx == NULL) {
		torture_comment(torture, "failed to create libnet context\n");
		ret = false;
		goto done;
	}

	ctx->cred = cmdline_credentials;

	mem_ctx = talloc_init("torture_domain_close_samr");
	status = dcerpc_pipe_connect_b(mem_ctx, &p, binding, &ndr_table_samr,
				     ctx->cred, torture->ev, torture->lp_ctx);
	if (!NT_STATUS_IS_OK(status)) {
		torture_comment(torture, "failed to connect to server: %s\n", nt_errstr(status));
		ret = false;
		goto done;
	}

	domain_name.string = talloc_strdup(mem_ctx, lpcfg_workgroup(torture->lp_ctx));

	if (!test_opendomain_samr(torture, p->binding_handle, torture, &h, &domain_name, &access_mask, &sid)) {
		torture_comment(torture, "failed to open domain on samr service\n");
		ret = false;
		goto done;
	}

	ctx->samr.pipe        = p;
	ctx->samr.name        = talloc_steal(ctx, domain_name.string);
	ctx->samr.access_mask = access_mask;
	ctx->samr.handle      = h;
	ctx->samr.sid         = talloc_steal(ctx, sid);

	ZERO_STRUCT(r);
	r.in.type = DOMAIN_SAMR;
	r.in.domain_name = domain_name.string;

	status = libnet_DomainClose(ctx, mem_ctx, &r);
	if (!NT_STATUS_IS_OK(status)) {
		ret = false;
		goto done;
	}

done:
	talloc_free(mem_ctx);
	talloc_free(ctx);
	return ret;
}
Beispiel #22
0
static bool sync_eventlog_params(TALLOC_CTX *mem_ctx,
				 struct messaging_context *msg_ctx,
				 EVENTLOG_INFO *info)
{
	struct dcerpc_binding_handle *h = NULL;
	uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
	struct policy_handle hive_hnd, key_hnd;
	uint32_t uiMaxSize = 0;
	uint32_t uiRetention = 0;
	char *path = NULL;
	NTSTATUS status;
	WERROR wresult = WERR_OK;
	char *elogname = info->logname;
	TALLOC_CTX *ctx;
	bool ret = false;

	ctx = talloc_stackframe();
	if (ctx == NULL) {
		return false;
	}

	DEBUG( 4, ( "sync_eventlog_params with %s\n", elogname ) );

	if ( !info->etdb ) {
		DEBUG( 4, ( "No open tdb! (%s)\n", info->logname ) );
		goto done;
	}
	/* set resonable defaults.  512Kb on size and 1 week on time */

	uiMaxSize = 0x80000;
	uiRetention = 604800;

	/* the general idea is to internally open the registry
	   key and retrieve the values.  That way we can continue
	   to use the same fetch/store api that we use in
	   srv_reg_nt.c */
	path = talloc_asprintf(ctx, "%s\\%s", TOP_LEVEL_EVENTLOG_KEY, elogname);
	if (!path) {
		goto done;
	}

	status = dcerpc_winreg_int_hklm_openkey(ctx,
						get_session_info_system(),
						msg_ctx,
						&h,
						path,
						false,
						access_mask,
						&hive_hnd,
						&key_hnd,
						&wresult);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(4,("sync_eventlog_params: Failed to open key [%s] (%s)\n",
			 path, nt_errstr(status)));
		goto done;
	}
	if ( !W_ERROR_IS_OK( wresult ) ) {
		DEBUG( 4,
		       ( "sync_eventlog_params: Failed to open key [%s] (%s)\n",
			 path, win_errstr( wresult ) ) );
		goto done;
	}

	status = dcerpc_winreg_query_dword(ctx,
					   h,
					   &key_hnd,
					   "Retention",
					   &uiRetention,
					   &wresult);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(4, ("Failed to query value \"Retention\": %s\n",
			  nt_errstr(status)));
		goto done;
	}
	if (!W_ERROR_IS_OK(wresult)) {
		DEBUG(4, ("Failed to query value \"Retention\": %s\n",
			  win_errstr(wresult)));
		goto done;
	}

	status = dcerpc_winreg_query_dword(ctx,
					   h,
					   &key_hnd,
					   "MaxSize",
					   &uiMaxSize,
					   &wresult);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(4, ("Failed to query value \"Retention\": %s\n",
			  nt_errstr(status)));
		goto done;
	}
	if (!W_ERROR_IS_OK(wresult)) {
		DEBUG(4, ("Failed to query value \"MaxSize\": %s\n",
			  win_errstr(wresult)));
		goto done;
	}

	tdb_store_int32( ELOG_TDB_CTX(info->etdb), EVT_MAXSIZE, uiMaxSize );
	tdb_store_int32( ELOG_TDB_CTX(info->etdb), EVT_RETENTION, uiRetention );

	ret = true;

done:
	if (h != NULL) {
		WERROR ignore;

		if (is_valid_policy_hnd(&key_hnd)) {
			dcerpc_winreg_CloseKey(h, ctx, &key_hnd, &ignore);
		}
		if (is_valid_policy_hnd(&hive_hnd)) {
			dcerpc_winreg_CloseKey(h, ctx, &hive_hnd, &ignore);
		}
	}

	TALLOC_FREE(ctx);
	return ret;
}
Beispiel #23
0
/*
  Modern, all singing, all dancing extended security (and possibly SPNEGO) request
*/
static NTSTATUS session_setup_spnego(struct composite_context *c,
				     struct smbcli_session *session, 
				     struct smb_composite_sesssetup *io,
				     struct smbcli_request **req) 
{
	struct sesssetup_state *state = talloc_get_type(c->private_data, struct sesssetup_state);
	NTSTATUS status;
	const char *chosen_oid = NULL;

	state->setup.spnego.level           = RAW_SESSSETUP_SPNEGO;
	state->setup.spnego.in.bufsize      = session->transport->options.max_xmit;
	state->setup.spnego.in.mpx_max      = session->transport->options.max_mux;
	state->setup.spnego.in.vc_num       = 1;
	state->setup.spnego.in.sesskey      = io->in.sesskey;
	state->setup.spnego.in.capabilities = io->in.capabilities;
	state->setup.spnego.in.os           = "Unix";
	state->setup.spnego.in.lanman       = talloc_asprintf(state, "Samba %s", SAMBA_VERSION_STRING);
	state->setup.spnego.in.workgroup    = io->in.workgroup;

	smbcli_temp_set_signing(session->transport);

	status = gensec_client_start(session, &session->gensec, c->event_ctx,
				     io->in.gensec_settings);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1, ("Failed to start GENSEC client mode: %s\n", nt_errstr(status)));
		return status;
	}

	gensec_want_feature(session->gensec, GENSEC_FEATURE_SESSION_KEY);

	status = gensec_set_credentials(session->gensec, io->in.credentials);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1, ("Failed to start set GENSEC client credentials: %s\n", 
			  nt_errstr(status)));
		return status;
	}

	status = gensec_set_target_hostname(session->gensec, session->transport->socket->hostname);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1, ("Failed to start set GENSEC target hostname: %s\n", 
			  nt_errstr(status)));
		return status;
	}

	status = gensec_set_target_service(session->gensec, "cifs");
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1, ("Failed to start set GENSEC target service: %s\n", 
			  nt_errstr(status)));
		return status;
	}

	if (session->transport->negotiate.secblob.length) {
		chosen_oid = GENSEC_OID_SPNEGO;
		status = gensec_start_mech_by_oid(session->gensec, chosen_oid);
		if (!NT_STATUS_IS_OK(status)) {
			DEBUG(1, ("Failed to start set GENSEC client mechanism %s: %s\n",
				  gensec_get_name_by_oid(session->gensec, chosen_oid), nt_errstr(status)));
			chosen_oid = GENSEC_OID_NTLMSSP;
			status = gensec_start_mech_by_oid(session->gensec, chosen_oid);
			if (!NT_STATUS_IS_OK(status)) {
				DEBUG(1, ("Failed to start set (fallback) GENSEC client mechanism %s: %s\n",
					  gensec_get_name_by_oid(session->gensec, chosen_oid), 
					  nt_errstr(status)));
			return status;
			}
		}
	} else {
		/* without a sec blob, means raw NTLMSSP */
		chosen_oid = GENSEC_OID_NTLMSSP;
		status = gensec_start_mech_by_oid(session->gensec, chosen_oid);
		if (!NT_STATUS_IS_OK(status)) {
			DEBUG(1, ("Failed to start set GENSEC client mechanism %s: %s\n",
				  gensec_get_name_by_oid(session->gensec, chosen_oid), nt_errstr(status)));
		}
	}

	if ((const void *)chosen_oid == (const void *)GENSEC_OID_SPNEGO) {
		status = gensec_update(session->gensec, state,
				       session->transport->negotiate.secblob,
				       &state->setup.spnego.in.secblob);
	} else {
		status = gensec_update(session->gensec, state,
				       data_blob(NULL, 0),
				       &state->setup.spnego.in.secblob);

	}

	if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) && 
	    !NT_STATUS_IS_OK(status)) {
		DEBUG(1, ("Failed initial gensec_update with mechanism %s: %s\n",
			  gensec_get_name_by_oid(session->gensec, chosen_oid), 
			  nt_errstr(status)));
		return status;
	}
	state->gensec_status = status;

	*req = smb_raw_sesssetup_send(session, &state->setup);
	if (!*req) {
		return NT_STATUS_NO_MEMORY;
	}

	/*
	 * we need to check the signature ourself
	 * as the session key might be the acceptor subkey
	 * which comes within the response itself
	 */
	(*req)->sign_caller_checks = true;

	return (*req)->status;
}
Beispiel #24
0
static bool elog_check_access( EVENTLOG_INFO *info, const struct security_token *token )
{
	char *tdbname = elog_tdbname(talloc_tos(), info->logname );
	struct security_descriptor *sec_desc;
	struct security_ace *ace;
	NTSTATUS status;

	if ( !tdbname )
		return False;

	/* get the security descriptor for the file */

	sec_desc = get_nt_acl_no_snum( info, tdbname );
	TALLOC_FREE( tdbname );

	if ( !sec_desc ) {
		DEBUG(5,("elog_check_access: Unable to get NT ACL for %s\n",
			tdbname));
		return False;
	}

	ace = talloc_zero(sec_desc, struct security_ace);
	if (ace == NULL) {
		TALLOC_FREE(sec_desc);
		return false;
	}

	ace->type		= SEC_ACE_TYPE_ACCESS_ALLOWED;
	ace->flags		= 0;
	ace->access_mask	= REG_KEY_ALL;
	ace->trustee		= global_sid_System;

	status = security_descriptor_dacl_add(sec_desc, ace);
	if (!NT_STATUS_IS_OK(status)) {
		TALLOC_FREE(sec_desc);
		return false;
	}

	/* root free pass */

	if ( geteuid() == sec_initial_uid() ) {
		DEBUG(5,("elog_check_access: running as root, using system token\n"));
		token = get_system_token();
	}

	/* run the check, try for the max allowed */

	status = se_access_check( sec_desc, token, MAXIMUM_ALLOWED_ACCESS,
		&info->access_granted);

	TALLOC_FREE(sec_desc);

	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(8,("elog_check_access: se_access_check() return %s\n",
			nt_errstr(status)));
		return False;
	}

	/* we have to have READ permission for a successful open */

	return ( info->access_granted & SEC_FILE_READ_DATA );
}
Beispiel #25
0
NTSTATUS delete_all_streams(connection_struct *conn, const char *fname)
{
	struct stream_struct *stream_info = NULL;
	int i;
	unsigned int num_streams = 0;
	TALLOC_CTX *frame = talloc_stackframe();
	NTSTATUS status;

	status = vfs_streaminfo(conn, NULL, fname, talloc_tos(),
				&num_streams, &stream_info);

	if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
		DEBUG(10, ("no streams around\n"));
		TALLOC_FREE(frame);
		return NT_STATUS_OK;
	}

	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(10, ("vfs_streaminfo failed: %s\n",
			   nt_errstr(status)));
		goto fail;
	}

	DEBUG(10, ("delete_all_streams found %d streams\n",
		   num_streams));

	if (num_streams == 0) {
		TALLOC_FREE(frame);
		return NT_STATUS_OK;
	}

	for (i=0; i<num_streams; i++) {
		int res;
		struct smb_filename *smb_fname_stream = NULL;

		if (strequal(stream_info[i].name, "::$DATA")) {
			continue;
		}

		status = create_synthetic_smb_fname(talloc_tos(), fname,
						    stream_info[i].name, NULL,
						    &smb_fname_stream);

		if (!NT_STATUS_IS_OK(status)) {
			DEBUG(0, ("talloc_aprintf failed\n"));
			goto fail;
		}

		res = SMB_VFS_UNLINK(conn, smb_fname_stream);

		if (res == -1) {
			status = map_nt_error_from_unix(errno);
			DEBUG(10, ("Could not delete stream %s: %s\n",
				   smb_fname_str_dbg(smb_fname_stream),
				   strerror(errno)));
			TALLOC_FREE(smb_fname_stream);
			break;
		}
		TALLOC_FREE(smb_fname_stream);
	}

 fail:
	TALLOC_FREE(frame);
	return status;
}
Beispiel #26
0
/*
  reply to a ADS style GETDC request
 */
static NTSTATUS nbtd_netlogon_samlogon(
	struct nbtd_server *nbtsrv,
	struct nbt_name *dst_name,
	const struct socket_address *src,
	struct nbt_netlogon_packet *netlogon,
	TALLOC_CTX *mem_ctx,
	struct nbt_netlogon_response **presponse,
	char **preply_mailslot)
{
	struct ldb_context *samctx;
	struct dom_sid *sid = NULL;
	struct nbt_netlogon_response *response = NULL;
	char *reply_mailslot = NULL;
	NTSTATUS status;

	/* only answer getdc requests on the PDC or LOGON names */
	if ((dst_name->type != NBT_NAME_PDC) &&
	    (dst_name->type != NBT_NAME_LOGON)) {
		return NT_STATUS_NOT_SUPPORTED;
	}

	samctx = nbtsrv->sam_ctx;

	if (netlogon->req.logon.sid_size != 0) {
		sid = &netlogon->req.logon.sid;
	}

	reply_mailslot = talloc_strdup(
		mem_ctx, netlogon->req.logon.mailslot_name);
	if (reply_mailslot == NULL) {
		return NT_STATUS_NO_MEMORY;
	}

	response = talloc_zero(mem_ctx, struct nbt_netlogon_response);
	if (response == NULL) {
		TALLOC_FREE(reply_mailslot);
		return NT_STATUS_NO_MEMORY;
	}
	response->response_type = NETLOGON_SAMLOGON;

	status = fill_netlogon_samlogon_response(
		samctx, response, NULL, dst_name->name, sid, NULL,
		netlogon->req.logon.user_name,
		netlogon->req.logon.acct_control, src->addr,
		netlogon->req.logon.nt_version, nbtsrv->task->lp_ctx,
		&response->data.samlogon, false);
	if (!NT_STATUS_IS_OK(status)) {
		char buf[DOM_SID_STR_BUFLEN];
		dom_sid_string_buf(sid, buf, sizeof(buf));

		DBG_NOTICE("NBT netlogon query failed domain=%s sid=%s "
			   "version=%d - %s\n", dst_name->name, buf,
			   netlogon->req.logon.nt_version, nt_errstr(status));
		TALLOC_FREE(reply_mailslot);
		TALLOC_FREE(response);
		return status;
	}

	*presponse = response;
	*preply_mailslot = reply_mailslot;
	return NT_STATUS_OK;
}
Beispiel #27
0
static NTSTATUS close_normal_file(struct smb_request *req, files_struct *fsp,
				  enum file_close_type close_type)
{
	NTSTATUS status = NT_STATUS_OK;
	NTSTATUS tmp;
	connection_struct *conn = fsp->conn;

	if (close_type == ERROR_CLOSE) {
		cancel_aio_by_fsp(fsp);
	} else {
		/*
	 	 * If we're finishing async io on a close we can get a write
		 * error here, we must remember this.
		 */
		int ret = wait_for_aio_completion(fsp);
		if (ret) {
			status = ntstatus_keeperror(
				status, map_nt_error_from_unix(ret));
		}
	}

	/*
	 * If we're flushing on a close we can get a write
	 * error here, we must remember this.
	 */

	tmp = close_filestruct(fsp);
	status = ntstatus_keeperror(status, tmp);

	if (fsp->print_file) {
		/* FIXME: return spool errors */
		print_spool_end(fsp, close_type);
		file_free(req, fsp);
		return NT_STATUS_OK;
	}

	/* Remove the oplock before potentially deleting the file. */
	if(fsp->oplock_type) {
		release_file_oplock(fsp);
	}

	/* If this is an old DOS or FCB open and we have multiple opens on
	   the same handle we only have one share mode. Ensure we only remove
	   the share mode on the last close. */

	if (fsp->fh->ref_count == 1) {
		/* Should we return on error here... ? */
		tmp = close_remove_share_mode(fsp, close_type);
		status = ntstatus_keeperror(status, tmp);
	}

	locking_close_file(conn->sconn->msg_ctx, fsp, close_type);

	tmp = fd_close(fsp);
	status = ntstatus_keeperror(status, tmp);

	/* check for magic scripts */
	if (close_type == NORMAL_CLOSE) {
		tmp = check_magic(fsp);
		status = ntstatus_keeperror(status, tmp);
	}

	/*
	 * Ensure pending modtime is set after close.
	 */

	tmp = update_write_time_on_close(fsp);
	if (NT_STATUS_EQUAL(tmp, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
		/* Someone renamed the file or a parent directory containing
		 * this file. We can't do anything about this, we don't have
		 * an "update timestamp by fd" call in POSIX. Eat the error. */

		tmp = NT_STATUS_OK;
	}

	status = ntstatus_keeperror(status, tmp);

	DEBUG(2,("%s closed file %s (numopen=%d) %s\n",
		conn->session_info->unix_info->unix_name, fsp_str_dbg(fsp),
		conn->num_files_open - 1,
		nt_errstr(status) ));

	file_free(req, fsp);
	return status;
}
Beispiel #28
0
static NTSTATUS nbtd_mailslot_netlogon_reply(
	struct nbtd_interface *iface,
	struct nbt_dgram_packet *packet,
	struct socket_address *src,
	TALLOC_CTX *mem_ctx,
	struct nbt_netlogon_response **presponse,
	char **preply_mailslot)
{
	struct nbt_netlogon_packet *netlogon;
	struct nbt_name *dst_name = &packet->data.msg.dest_name;
	struct nbt_netlogon_response *response = NULL;
	struct nbtd_iface_name *iname;
	char *reply_mailslot = NULL;
	NTSTATUS status;

	/*
	  see if the we are listening on the destination netbios name
	*/
	iname = nbtd_find_iname(iface, dst_name, 0);
	if (iname == NULL) {
		return NT_STATUS_BAD_NETWORK_NAME;
	}

	netlogon = talloc(mem_ctx, struct nbt_netlogon_packet);
	if (netlogon == NULL) {
		return NT_STATUS_NO_MEMORY;
	}

	status = dgram_mailslot_netlogon_parse_request(netlogon, packet,
						       netlogon);
	if (!NT_STATUS_IS_OK(status)) {
		goto failed;
	}

	switch (netlogon->command) {
	case LOGON_PRIMARY_QUERY:
		status = nbtd_netlogon_getdc(
			iface->nbtsrv, &packet->data.msg.dest_name,
			netlogon, mem_ctx, &response, &reply_mailslot);
		break;
	case LOGON_SAM_LOGON_REQUEST:
		status = nbtd_netlogon_samlogon(
			iface->nbtsrv, &packet->data.msg.dest_name, src,
			netlogon, mem_ctx, &response, &reply_mailslot);
		break;
	default:
		DEBUG(2,("unknown netlogon op %d from %s:%d\n",
			 netlogon->command, src->addr, src->port));
		NDR_PRINT_DEBUG(nbt_netlogon_packet, netlogon);
		status = NT_STATUS_NOT_SUPPORTED;
		break;
	}

	if (!NT_STATUS_IS_OK(status)) {
		DBG_DEBUG("Calculating reply failed: %s\n",
			  nt_errstr(status));
		goto failed;
	}

	*presponse = response;
	*preply_mailslot = reply_mailslot;
	return NT_STATUS_OK;

failed:
	TALLOC_FREE(reply_mailslot);
	TALLOC_FREE(netlogon);
	return status;
}
Beispiel #29
0
NTSTATUS _net_sam_logon(pipes_struct *p, NET_Q_SAM_LOGON *q_u, NET_R_SAM_LOGON *r_u)
{
	NTSTATUS status = NT_STATUS_OK;
	NET_USER_INFO_3 *usr_info = NULL;
	NET_ID_INFO_CTR *ctr = q_u->sam_id.ctr;
	DOM_CRED srv_cred;
	UNISTR2 *uni_samlogon_user = NULL;
	UNISTR2 *uni_samlogon_domain = NULL;
	UNISTR2 *uni_samlogon_workstation = NULL;
	fstring nt_username, nt_domain, nt_workstation;
	auth_usersupplied_info *user_info = NULL;
	auth_serversupplied_info *server_info = NULL;
	extern userdom_struct current_user_info;
	SAM_ACCOUNT *sampw;
	struct auth_context *auth_context = NULL;
	        
	usr_info = (NET_USER_INFO_3 *)talloc(p->mem_ctx, sizeof(NET_USER_INFO_3));
	if (!usr_info)
		return NT_STATUS_NO_MEMORY;

	ZERO_STRUCTP(usr_info);

 	/* store the user information, if there is any. */
	r_u->user = usr_info;
	r_u->switch_value = 0; /* indicates no info */
	r_u->auth_resp = 1; /* authoritative response */
	r_u->switch_value = 3; /* indicates type of validation user info */
 
	if (!get_valid_user_struct(p->vuid))
		return NT_STATUS_NO_SUCH_USER;


	if ( (lp_server_schannel() == True) && (!p->netsec_auth_validated) ) {
		/* 'server schannel = yes' should enforce use of
		   schannel, the client did offer it in auth2, but
		   obviously did not use it. */
		return NT_STATUS_ACCESS_DENIED;
	}

	/* checks and updates credentials.  creates reply credentials */
	if (!(p->dc.authenticated && deal_with_creds(p->dc.sess_key, &p->dc.clnt_cred, &q_u->sam_id.client.cred, &srv_cred)))
		return NT_STATUS_INVALID_HANDLE;

	memcpy(&p->dc.srv_cred, &p->dc.clnt_cred, sizeof(p->dc.clnt_cred));
    
	r_u->buffer_creds = 1; /* yes, we have valid server credentials */
	memcpy(&r_u->srv_creds, &srv_cred, sizeof(r_u->srv_creds));

	/* find the username */
    
	switch (q_u->sam_id.logon_level) {
	case INTERACTIVE_LOGON_TYPE:
		uni_samlogon_user = &ctr->auth.id1.uni_user_name;
 		uni_samlogon_domain = &ctr->auth.id1.uni_domain_name;

                uni_samlogon_workstation = &ctr->auth.id1.uni_wksta_name;
            
		DEBUG(3,("SAM Logon (Interactive). Domain:[%s].  ", lp_workgroup()));
		break;
	case NET_LOGON_TYPE:
		uni_samlogon_user = &ctr->auth.id2.uni_user_name;
		uni_samlogon_domain = &ctr->auth.id2.uni_domain_name;
		uni_samlogon_workstation = &ctr->auth.id2.uni_wksta_name;
            
		DEBUG(3,("SAM Logon (Network). Domain:[%s].  ", lp_workgroup()));
		break;
	default:
		DEBUG(2,("SAM Logon: unsupported switch value\n"));
		return NT_STATUS_INVALID_INFO_CLASS;
	} /* end switch */

	rpcstr_pull(nt_username,uni_samlogon_user->buffer,sizeof(nt_username),uni_samlogon_user->uni_str_len*2,0);
	rpcstr_pull(nt_domain,uni_samlogon_domain->buffer,sizeof(nt_domain),uni_samlogon_domain->uni_str_len*2,0);
	rpcstr_pull(nt_workstation,uni_samlogon_workstation->buffer,sizeof(nt_workstation),uni_samlogon_workstation->uni_str_len*2,0);

	DEBUG(3,("User:[%s@%s] Requested Domain:[%s]\n", nt_username, 
                 nt_workstation, nt_domain));
   	
	fstrcpy(current_user_info.smb_name, nt_username);
	sub_set_smb_name(nt_username);
     
	DEBUG(5,("Attempting validation level %d for unmapped username %s.\n", q_u->sam_id.ctr->switch_value, nt_username));

	status = NT_STATUS_OK;
	
	switch (ctr->switch_value) {
	case NET_LOGON_TYPE:
	{
		const char *wksname = nt_workstation;
		
		if (!NT_STATUS_IS_OK(status = make_auth_context_fixed(&auth_context, ctr->auth.id2.lm_chal))) {
			return status;
		}

		/* For a network logon, the workstation name comes in with two
		 * backslashes in the front. Strip them if they are there. */

		if (*wksname == '\\') wksname++;
		if (*wksname == '\\') wksname++;

		/* Standard challenge/response authenticaion */
		if (!make_user_info_netlogon_network(&user_info, 
						     nt_username, nt_domain, 
						     wksname,
						     ctr->auth.id2.lm_chal_resp.buffer,
						     ctr->auth.id2.lm_chal_resp.str_str_len,
						     ctr->auth.id2.nt_chal_resp.buffer,
						     ctr->auth.id2.nt_chal_resp.str_str_len)) {
			status = NT_STATUS_NO_MEMORY;
		}	
		break;
	}
	case INTERACTIVE_LOGON_TYPE:
		/* 'Interactive' autheticaion, supplies the password in its
		   MD4 form, encrypted with the session key.  We will
		   convert this to chellange/responce for the auth
		   subsystem to chew on */
	{
		const uint8 *chal;
		
		if (!NT_STATUS_IS_OK(status = make_auth_context_subsystem(&auth_context))) {
			return status;
		}
		
		chal = auth_context->get_ntlm_challenge(auth_context);

		if (!make_user_info_netlogon_interactive(&user_info, 
							 nt_username, nt_domain, 
							 nt_workstation, chal,
							 ctr->auth.id1.lm_owf.data, 
							 ctr->auth.id1.nt_owf.data, 
							 p->dc.sess_key)) {
			status = NT_STATUS_NO_MEMORY;
		}
		break;
	}
	default:
		DEBUG(2,("SAM Logon: unsupported switch value\n"));
		return NT_STATUS_INVALID_INFO_CLASS;
	} /* end switch */
	
	if ( NT_STATUS_IS_OK(status) ) {
		status = auth_context->check_ntlm_password(auth_context, 
			user_info, &server_info);
	}

	(auth_context->free)(&auth_context);	
	free_user_info(&user_info);
	
	DEBUG(5, ("_net_sam_logon: check_password returned status %s\n", 
		  nt_errstr(status)));

	/* Check account and password */
    
	if (!NT_STATUS_IS_OK(status)) {
		free_server_info(&server_info);
		return status;
	}

	if (server_info->guest) {
		/* We don't like guest domain logons... */
		DEBUG(5,("_net_sam_logon: Attempted domain logon as GUEST denied.\n"));
		free_server_info(&server_info);
		return NT_STATUS_LOGON_FAILURE;
	}

	/* This is the point at which, if the login was successful, that
           the SAM Local Security Authority should record that the user is
           logged in to the domain.  */
    
	{
		DOM_GID *gids = NULL;
		const DOM_SID *user_sid = NULL;
		const DOM_SID *group_sid = NULL;
		DOM_SID domain_sid;
		uint32 user_rid, group_rid; 

		int num_gids = 0;
		pstring my_name;
		fstring user_sid_string;
		fstring group_sid_string;
		uchar user_session_key[16];
		uchar lm_session_key[16];
		uchar netlogon_sess_key[16];

		sampw = server_info->sam_account;

		/* set up pointer indicating user/password failed to be found */
		usr_info->ptr_user_info = 0;

		user_sid = pdb_get_user_sid(sampw);
		group_sid = pdb_get_group_sid(sampw);

		sid_copy(&domain_sid, user_sid);
		sid_split_rid(&domain_sid, &user_rid);

		if (!sid_peek_check_rid(&domain_sid, group_sid, &group_rid)) {
			DEBUG(1, ("_net_sam_logon: user %s\\%s has user sid %s\n but group sid %s.\nThe conflicting domain portions are not supported for NETLOGON calls\n", 	    
				  pdb_get_domain(sampw), pdb_get_username(sampw),
				  sid_to_string(user_sid_string, user_sid),
				  sid_to_string(group_sid_string, group_sid)));
			return NT_STATUS_UNSUCCESSFUL;
		}
		
		pstrcpy(my_name, global_myname());

		if (!NT_STATUS_IS_OK(status 
				     = nt_token_to_group_list(p->mem_ctx, 
							      &domain_sid, 
							      server_info->ptok, 
							      &num_gids, 
							      &gids))) {
			return status;
		}

		ZERO_STRUCT(netlogon_sess_key);
		memcpy(netlogon_sess_key, p->dc.sess_key, 8);
		if (server_info->user_session_key.length) {
			memcpy(user_session_key, server_info->user_session_key.data, 
			       MIN(sizeof(user_session_key), server_info->user_session_key.length));
			SamOEMhash(user_session_key, netlogon_sess_key, 16);
		}
		if (server_info->lm_session_key.length) {
			memcpy(lm_session_key, server_info->lm_session_key.data, 
			       MIN(sizeof(lm_session_key), server_info->lm_session_key.length));
			SamOEMhash(lm_session_key, netlogon_sess_key, 16);
		}
		ZERO_STRUCT(netlogon_sess_key);
		
		init_net_user_info3(p->mem_ctx, usr_info, 
				    user_rid,
				    group_rid,   
				    pdb_get_username(sampw),
				    pdb_get_fullname(sampw),
				    pdb_get_homedir(sampw),
				    pdb_get_dir_drive(sampw),
				    pdb_get_logon_script(sampw),
				    pdb_get_profile_path(sampw),
				    pdb_get_logon_time(sampw),
				    get_time_t_max(),
				    get_time_t_max(),
				    pdb_get_pass_last_set_time(sampw),
				    pdb_get_pass_can_change_time(sampw),
				    pdb_get_pass_must_change_time(sampw),
				    
				    0, /* logon_count */
				    0, /* bad_pw_count */
				    num_gids,    /* uint32 num_groups */
				    gids    , /* DOM_GID *gids */
				    0x20    , /* uint32 user_flgs (?) */
				    server_info->user_session_key.length ? user_session_key : NULL,
				    server_info->lm_session_key.length ? lm_session_key : NULL,
				    my_name     , /* char *logon_srv */
				    pdb_get_domain(sampw),
				    &domain_sid,     /* DOM_SID *dom_sid */  
				    /* Should be users domain sid, not servers - for trusted domains */
				  
				    NULL); /* char *other_sids */
		ZERO_STRUCT(user_session_key);
		ZERO_STRUCT(lm_session_key);
	}
	free_server_info(&server_info);
	return status;
}
Beispiel #30
0
/* convert a single name to a sid in a domain */
NTSTATUS rpc_name_to_sid(TALLOC_CTX *mem_ctx,
			 struct rpc_pipe_client *lsa_pipe,
			 struct policy_handle *lsa_policy,
			 const char *domain_name,
			 const char *name,
			 uint32_t flags,
			 struct dom_sid *sid,
			 enum lsa_SidType *type)
{
	enum lsa_SidType *types = NULL;
	struct dom_sid *sids = NULL;
	char *full_name = NULL;
	const char *names[1];
	char *mapped_name = NULL;
	NTSTATUS status;

	if (name == NULL || name[0] == '\0') {
		full_name = talloc_asprintf(mem_ctx, "%s", domain_name);
	} else if (domain_name == NULL || domain_name[0] == '\0') {
		full_name = talloc_asprintf(mem_ctx, "%s", name);
	} else {
		full_name = talloc_asprintf(mem_ctx, "%s\\%s", domain_name, name);
	}

	if (full_name == NULL) {
		return NT_STATUS_NO_MEMORY;
	}

	status = normalize_name_unmap(mem_ctx, full_name, &mapped_name);
	/* Reset the full_name pointer if we mapped anything */
	if (NT_STATUS_IS_OK(status) ||
	    NT_STATUS_EQUAL(status, NT_STATUS_FILE_RENAMED)) {
		full_name = mapped_name;
	}

	DEBUG(3,("name_to_sid: %s for domain %s\n",
		 full_name ? full_name : "", domain_name ));

	names[0] = full_name;

	/*
	 * We don't run into deadlocks here, cause winbind_off() is
	 * called in the main function.
	 */
	status = rpccli_lsa_lookup_names(lsa_pipe,
					 mem_ctx,
					 lsa_policy,
					 1, /* num_names */
					 names,
					 NULL, /* domains */
					 1, /* level */
					 &sids,
					 &types);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(2,("name_to_sid: failed to lookup name: %s\n",
			nt_errstr(status)));
		return status;
	}

	sid_copy(sid, &sids[0]);
	*type = types[0];

	return NT_STATUS_OK;
}