I am using shell script scp command to move one file from one server to another using ssh.
My command looks like this:
scp -P 23 -i $TEST_SSHKEY $DESTINATION_PATH/$FILETOCOPY $USER_ID#$SERVER_BOX:
File is copying but scp is returning return code as 1.
Why it is happening and what is the solution for this?
G'day,
Try enabling verbose mode (-v) to see more details of what's going on rather than just looking at a return code of 1 which means "something bad happened".
I have this same issue. The problem is the server on the remote end not sending an exit code. Compare these transaction excerpts.
The first causes $? = 1:
debug1: Sending command: scp -v -f /cfg/running-config
Sink: C0644 3398 running-config
running-config 100% 3398 3.3KB/s 00:00
debug1: channel 0: free: client-session, nchannels 1
debug1: fd 0 clearing O_NONBLOCK
debug1: fd 1 clearing O_NONBLOCK
Connection to xxxxx closed by remote host.
Transferred: sent 2576, received 5216 bytes, in 1.9 seconds
Bytes per second: sent 1346.9, received 2727.3
debug1: Exit status -1
The second causes $?=0:
debug1: Sending command: scp -v -f /cfg/running-config
Sink: C0644 3940 running-config
running-config 100% 3940 3.9KB/s 00:00
debug1: client_input_channel_req: channel 0 rtype exit-status reply 0
debug1: channel 0: free: client-session, nchannels 1
debug1: fd 0 clearing O_NONBLOCK
debug1: fd 1 clearing O_NONBLOCK
Connection to xxxxx closed by remote host.
Transferred: sent 2624, received 5984 bytes, in 1.3 seconds
Bytes per second: sent 2026.8, received 4622.2
These are two HP switches on different firmware versions. The first one is very old; the second one is new and correctly returns exit-status reply 0 to the client.
Related
I'm trying to implement SSH server which acts as SCP sink (without calling external scp command) in GO.
I've ended up in partially working code:
https://gist.github.com/Seitanas/ad02158e8d5d2acedd9e7973ae44c77c.
The problem is that when I try to scp file to this service, local scp client copies data correctly but returns 1.
I think something happens at channel close. Maybe I'm missing something inside SCP protocol?
I'm guessing that ssh returns -1 and then scp exits with 1
Testing results:
echo "contents"> test.txt
scp -v -P2222 test.txt foo#127.0.0.1:/
Executing: program /usr/bin/ssh host 127.0.0.1, user foo, command scp -v -t /
...
debug1: SSH2_MSG_SERVICE_ACCEPT received
debug1: Authentications that can continue: password
debug1: Next authentication method: password
foo#127.0.0.1's password:
debug1: Authentication succeeded (password).
Authenticated to 127.0.0.1 ([127.0.0.1]:2222).
debug1: channel 0: new [client-session]
debug1: Requesting no-more-sessions#openssh.com
debug1: Entering interactive session.
debug1: pledge: network
debug1: Sending environment.
debug1: Sending env LC_TERMINAL_VERSION = 3.4.12
debug1: Sending env LC_CTYPE = en_US.UTF-8
debug1: Sending env LC_TERMINAL = iTerm2
debug1: Sending command: scp -v -t /
Sending file modes: C0644 9 test.txt
test.txt 0% 0 0.0KB/s --:-- ETAdebug1: channel 0: free: client-session, nchannels 1
test.txt 100% 9 21.4KB/s 00:00
debug1: fd 0 clearing O_NONBLOCK
Transferred: sent 2032, received 1116 bytes, in 0.0 seconds
Bytes per second: sent 1245098.0, received 683823.5
debug1: Exit status -1
echo $?
1
Output from go code:
go run test.go
2022/02/15 17:17:21 Command: C
2022/02/15 17:17:21 File info: 0644 9 test.txt
2022/02/15 17:17:21 File size: 9
2022/02/15 17:17:21 Content: contents
Thank you for any ideas.
Right, I've found what the problem is.
I've forgot that I'm simulating SCP binary ant server side, so i need to simulate its exit code also.
So I've added additional line at the end:
channel.SendRequest("exit-status", false, []byte{0, 0, 0, 0})
This will send exit 0 status via channel.
Without it SCP at client side was waiting for remote transfer to finish, but socket was closing right after transfer without exit code.
Now everything works as expected:
debug1: Sending command: scp -v -t /
Sending file modes: C0644 9 test.txt
test.txt 0% 0 0.0KB/s --:-- ETAdebug1: client_input_channel_req: channel 0 rtype exit-status reply 0
debug1: channel 0: free: client-session, nchannels 1
test.txt 100% 9 14.1KB/s 00:00
debug1: fd 0 clearing O_NONBLOCK
Transferred: sent 2152, received 1172 bytes, in 0.0 seconds
Bytes per second: sent 1391979.3, received 758085.4
debug1: Exit status 0
I'm trying to set sftpuser restricted by ChrootDirectory on AIX7.1. But it's not working and shown "connection to localhost closed by remote host"
Now, I configurated in /etc/ssh/sshd_config
Match User testuser
ChrootDirectory /Share
ForceCommand internal-sftp
AllowTcpForwarding no
X11Forwarding no
The /Share owner by root user and permission is 755 but it's still not working and show debug as below.
sftp -vvv testuser#localhost
OpenSSH_8.1p1, OpenSSL 1.0.2u 20 Dec 2019
debug1: Authentication succeeded (password).
Authenticated to localhost ([127.0.0.1]:22).
debug2: fd 5 setting O_NONBLOCK
debug3: fd 6 is O_NONBLOCK
debug1: channel 0: new [client-session]
debug3: ssh_session2_open: channel_new: 0
debug2: channel 0: send open
debug3: send packet: type 90
debug1: Requesting no-more-sessions#openssh.com
debug3: send packet: type 80
debug1: fd 0 clearing O_NONBLOCK
debug3: fd 1 is not O_NONBLOCK
Connection to localhost closed by remote host.
Transferred: sent 2256, received 2228 bytes, in 0.0 seconds
Bytes per second: sent 270661.7, received 267302.4
debug1: Exit status -1
Connection closed
How can I solve it? Thanks in advance for your help.
I was not even able to do git push or ferch once. I enter password and its return error:
"fatal: the remote end hung up unexpectedly"
1.) I am login as admin using just password (no ssh keys)
2.) I can connect with ssh with no problems. Can create, delete dirs... whatever...
3.) When try to push by git fatal error appear
4.) I am connecting from same machine for eleminating compatibility or network errors
5.) When use no ssh, just path "d:/git-repos/git-local.git", git working nice
SSH debug log:
debug3: Ignored env SSH_AUTH_SOCK
debug1: Sending command: powershell git-upload-pack 'd:/git-repos/git-local.git'
debug2: channel 0: request exec confirm 1
debug3: send packet: type 98
debug2: channel_input_open_confirmation: channel 0: callback done
debug2: channel 0: open confirm rwindow 0 rmax 32768
debug2: channel 0: rcvd adjust 2097152
debug3: receive packet: type 99
debug2: channel_input_status_confirm: type 99 id 0
debug2: exec request accepted on channel 0
debug2: channel 0: read<=0 rfd 4 len 0
debug2: channel 0: read failed
debug2: channel 0: chan_shutdown_read (i0 o0 sock -1 wfd 4 efd 6 [write])
debug2: channel 0: input open -> drain
debug2: channel 0: ibuf empty
debug2: channel 0: send eof
debug3: send packet: type 96
debug2: channel 0: input drain -> closed
debug2: channel 0: rcvd ext data 43
fatal: the remote end hung up unexpectedly
debug2: channel 0: written 43 to efd 6
debug3: receive packet: type 96
debug2: channel 0: rcvd eof
debug2: channel 0: output open -> drain
debug2: channel 0: obuf empty
debug2: channel 0: chan_shutdown_write (i3 o1 sock -1 wfd 5 efd 6 [write])
debug2: channel 0: output drain -> closed
debug3: receive packet: type 98
debug1: client_input_channel_req: channel 0 rtype exit-status reply 0
debug3: receive packet: type 97
debug2: channel 0: rcvd close
debug3: channel 0: will not send data after close
debug2: channel 0: almost dead
debug2: channel 0: gc: notify user
debug2: channel 0: gc: user detached
debug2: channel 0: send close
debug3: send packet: type 97
debug2: channel 0: is dead
debug2: channel 0: garbage collecting
debug1: channel 0: free: client-session, nchannels 1
debug3: channel 0: status: The following connections are open:
#0 client-session (t4 r0 i3/0 o3/0 e[write]/0 fd -1/-1/6 sock -1 cc -1)
debug3: send packet: type 1
debug3: fd 0 is not O_NONBLOCK
Transferred: sent 2064, received 2528 bytes, in 0.8 seconds
Bytes per second: sent 2580.9, received 3161.1
debug1: Exit status 1
SSH server config:
# This is the sshd server system-wide configuration file. See
# sshd_config(5) for more information.
# The strategy used for options in the default sshd_config shipped with
# OpenSSH is to specify options with their default value where
# possible, but leave them commented. Uncommented options override the
# default value.
#Port 22
#AddressFamily any
#ListenAddress 0.0.0.0
#ListenAddress ::
#HostKey __PROGRAMDATA__/ssh/ssh_host_rsa_key
#HostKey __PROGRAMDATA__/ssh/ssh_host_dsa_key
#HostKey __PROGRAMDATA__/ssh/ssh_host_ecdsa_key
#HostKey __PROGRAMDATA__/ssh/ssh_host_ed25519_key
# Ciphers and keying
#RekeyLimit default none
# Logging
SyslogFacility LOCAL0
LogLevel DEBUG3
# Authentication:
#LoginGraceTime 2m
#PermitRootLogin prohibit-password
#StrictModes yes
#MaxAuthTries 6
#MaxSessions 10
# PubkeyAuthentication yes
# The default is to check both .ssh/authorized_keys and .ssh/authorized_keys2
# but this is overridden so installations will only check .ssh/authorized_keys
AuthorizedKeysFile .ssh/authorized_keys
#AuthorizedPrincipalsFile none
# For this to work you will also need host keys in %programData%/ssh/ssh_known_hosts
#HostbasedAuthentication no
# Change to yes if you don't trust ~/.ssh/known_hosts for
# HostbasedAuthentication
#IgnoreUserKnownHosts no
# Don't read the user's ~/.rhosts and ~/.shosts files
#IgnoreRhosts yes
# To disable tunneled clear text passwords, change to no here!
# PasswordAuthentication yes
# PermitEmptyPasswords no
# GSSAPI options
#GSSAPIAuthentication no
#AllowAgentForwarding yes
#AllowTcpForwarding yes
#GatewayPorts no
#PermitTTY yes
#PrintMotd yes
#PrintLastLog yes
#TCPKeepAlive yes
#UseLogin no
#PermitUserEnvironment no
#ClientAliveInterval 0
#ClientAliveCountMax 3
#UseDNS no
#PidFile /var/run/sshd.pid
#MaxStartups 10:30:100
#PermitTunnel no
#ChrootDirectory none
#VersionAddendum none
# no default banner path
#Banner none
# override default of no subsystems
Subsystem sftp sftp-server.exe
# Example of overriding settings on a per-user basis
#Match User anoncvs
# AllowTcpForwarding no
# PermitTTY no
# ForceCommand cvs server
#AllowUsers user
Match User user
ChrootDirectory "D:\git-repos"
Match User supreme
ChrootDirectory "D:\git-repos"
Match Group administrators
AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys
Seems to fail on command: powershell git-receive-pack 'D:/git-repos/git-local.git'
When run command from cmd it returns:
00bdd268299939f6e8bea6ae3e78cf891b59cc79da28 refs/heads/master report-status rep
ort-status-v2 delete-refs side-band-64k quiet atomic ofs-delta object-format=sha
1 agent=git/2.30.0.windows.1
OS: Windows 7 Ultimate SP1 32bit
Using Windows 7 CMD
Git version: 2.30.0 (32bit)
OpenSSH: 8.1p1 for Windows (32bit)
Installed by this guide:
https://github.com/PowerShell/Win32-OpenSSH/wiki/Setting-up-a-Git-server-on-Windows-using-Git-for-Windows-and-Win32_OpenSSH
First I install with no option "Run Git and included Unix tools from the Windows Command Prompt". But I reinstalled it later with this option.
Env Path server:
%SYSTEMROOT%\System32\WindowsPowerShell\v1.0\;
C:\ProgramsInstall\OpenSSH-Win32;
C:\ProgramsInstall\Git\cmd;
C:\ProgramsInstall\Git\mingw32\bin;
C:\ProgramsInstall\Git\usr\bin
"SSH where" command output:
C:\ProgramsInstall\OpenSSH-Win32\ssh.exe
C:\ProgramsInstall\Git\usr\bin\ssh.exe
Local repo config:
sshCommand = 'C:\\ProgramsInstall\\OpenSSH-Win32\\ssh.exe' -T -vvv
url = supreme#dev-server:D:/git-repos/git-local.git
uploadpack = powershell git-upload-pack
receivepack = powershell git-receive-pack
I would like to create a server process with Go which can receive or send files via scp, like:
scp -P 2200 -i ssh/tester_rsa foo#localhost:/test output.txt
or
scp -P 2200 -i ssh/tester_rsa input.txt foo#localhost:/test
With help of this gist I was already able to create an interactive ssh server which is able to accpet connections/commands via
ssh -i ssh/tester_rsa foo#localhost -p 2200 'somecommand'
and works nicely.
I understood that the payload contains "scp -f /test" for the first shown scp request. I am stuck in how to return actual content from the server, I tried in replying with a string (as with a normal ssh reply) but I get no file back.
Here my output of scp -vv
...
debug2: callback done
debug2: channel 0: open confirm rwindow 2097152 rmax 32768
debug2: channel_input_status_confirm: type 99 id 0
debug2: exec request accepted on channel 0
debug1: client_input_channel_req: channel 0 rtype exit-status reply 0
debug2: channel 0: rcvd close
debug2: channel 0: output open -> drain
debug2: channel 0: close_read
...
When I am trying with a propper server I get following lines
...
debug2: exec request accepted on channel 0
debug2: channel 0: rcvd ext data 43
Sending file modes: C0644 98 output.txt
debug2: channel 0: written 43 to efd 7
Sink: C0644 98 output.txt
output.txt
debug1: client_input_channel_req: channel 0 rtype exit-status reply 0
debug1: client_input_channel_req: channel 0 rtype eow#openssh.com reply 0
debug2: channel 0: rcvd eow
debug2: channel 0: close_read
...
So I guess I am missing some protocol / flow parameters or commands in Go.
Only the snippet of Go Code, as project is huge and is not easy to copy and paste here:
func (a *Shell) handleExec(connection ssh.Channel, payload []byte) {
...
for _, c := range a.ExecCmds {
if matchCmds(str, c.Cmd) {
connection.Write([]byte("Here comes the file content")
}
}
...
I know that the code is not right for scp, but it works fine for normal ssh. I don't know how to handle the connection, and what exactly to return so that a correct file transfer is done.
Googling for a while led me to this question on stack overflow which is nearly the same but got not completely answered, as I am exactly looking for the part
runYourCommand(msg.Command, ch)
which I guess contains the logic :)
Update: I am looking not for external ressources any more, I got some more input from this java snippet
It looks like they are emulating the scp protocol and I would perfectly be fine to have someone helping me to translate it to Go:
StringBuilder params = new StringBuilder("C0").append(perms);
params.append(" ").append(data.length).append(" ");
params.append(remoteFileName).append("\n");
out.write(params.toString().getBytes());
out.flush();
if (!waitForInputStream(logger, in)) {
cleanup(logger, out, channel);
logger.log(Level.SEVERE, "Error before writing SCP bytes");
return UNKNOWN_ERROR; /* TODO: Improve */
}
out.write(data);
out.write(new byte[]{0}, 0, 1);
out.flush();
I tried this so far, but didn't help
o:="Some content of a faked file"
connection.Write([]byte("C0644 "+string(len(o))+"test.txt\n"))
connection.Write([]byte(o))
connection.Write([]byte{0,0,1})
To clarify: I would not like to serve a real file, rather then Go simulating a file delivery over scp (using a string as the content of the file).
Thanks in advance!
Ok, found myself the solution, small but that made the code work:
prep := "C0644 " + strconv.Itoa(len(o)) + " test.txt\n"
connection.Write([]byte(prep))
connection.Write([]byte(o))
connection.Write([]byte("\x00"))
I was missing a space in prep variable after length, the length was not converted correctly and the closing "\x00" is working better this way. Now I am able to receive a fake file with content :)
I doubt that I'll get an answer here as AIX is very rare thing but I should try at least.
The background
We have the program. The program uses golang.org/x/crypto/ssh library to connect to the remote services and do some things. The program is part of the large service and widely tested by end-users. It works without issues (at least related to connection) not only with all Linux-based clients (include quite old things like Ubuntu 12.02) but also with the clients on FreeBSD, OpenBSD, NetBSD, MacOSX, Solaris SPARC, HP-UX and other *nixes. So looks like it wasn't tested only on the Samsung refrigerators. And yesterday I was sure that it will be able to connect to the refrigerator and do what is needed without any issues. But that was yesterday...
The problem
Today we decided to add AIX support to our program. And we partly failed.
The problem description is simple: after pty request program stops working. I mean I can do ssh.RequestPty it executes without any issues but when I'm trying to execute commands after the app just hangs. Without errors, without nothing. Just hangs.
When it works?
It works in PuTTY/KiTTY so I'm able to connect to the remote host.
If I remove requestPty - everything works. But we need pty for the sudo.
It works without issues if I request session.Shell even with pty requested. So if I write kind of interactive shell, it works perfectly.
What have I tried so far
I tried to debug so far as I could. The last command that executes is ch.sendMessage(msg) from ssh/channel.go. I mean it writes packet and that's all. No data returned from the remote host.
For the tests, I used 3 versions of AIX - 5.3, 6.1 and 7.1. No difference.
OpenSSH versions are different:
5.3 - OpenSSH_5.2p1, OpenSSL 0.9.8k 25 Mar 2009
6.1 & 7.1 - OpenSSH_6.0p1, OpenSSL 1.0.1e 11 Feb 2013
All machines are running in LPARs but I doubt this is related to the issue.
I have no idea what is wrong. And I even can't say if this is common AIX issue or only our test machine. Here is the sample program that should write IT WORKS if it works
package main
import (
"golang.org/x/crypto/ssh"
)
func main() {
server := "127.0.0.1:22"
user := "root"
p := "password"
config := &ssh.ClientConfig{
User: user,
Auth: []ssh.AuthMethod{ssh.Password(p)},
}
conn, err := ssh.Dial("tcp", server, config)
if err != nil {
panic(err.Error())
}
defer conn.Close()
session, err := conn.NewSession()
if err != nil {
panic(err.Error())
}
defer session.Close()
// Comment below and everything works
modes := ssh.TerminalModes{
ssh.ECHO: 0,
ssh.TTY_OP_ISPEED: 14400,
ssh.TTY_OP_OSPEED: 14400,
}
if err := session.RequestPty("xterm", 80, 40, modes); err != nil {
panic(err.Error())
}
// Comment above and everything works
session.Run("echo 1")
println("IT WORKS")
}
If you have AIX somewhere around and can run this code against it I'd appreciate your feedback.
If you have any ideas (even crazy) why it may fail and where else I can look, don't be shy.
Update (2017-03-02):
By suggestion from #LorinczyZsigmond I launched sshd in debug mode. Results are a bit strange.
Here is part of Debian 9.0 OpenSSH_6.0p1 Debian-4+deb7u3, OpenSSL 1.0.1t 3 May 2016 log after sample program execution:
debug1: session_input_channel_req: session 0 req pty-req
debug1: Allocating pty.
debug1: session_pty_req: session 0 alloc /dev/pts/1
debug1: SELinux support disabled
debug1: server_input_channel_req: channel 0 request exec reply 1
debug1: session_by_channel: session 0 channel 0
debug1: session_input_channel_req: session 0 req exec
debug2: fd 3 setting TCP_NODELAY
debug3: packet_set_tos: set IP_TOS 0x10
debug1: Setting controlling tty using TIOCSCTTY.
debug2: channel 0: rfd 10 isatty
debug2: fd 10 setting O_NONBLOCK
debug3: fd 8 is O_NONBLOCK
debug2: channel 0: rcvd eof
debug2: channel 0: output open -> drain
It works as expected.
Now the same block from AIX 7.1 OpenSSH_6.0p1, OpenSSL 1.0.1e 11 Feb 2013 log:
debug1: session_input_channel_req: session 0 req pty-req
debug1: Allocating pty.
debug1: session_pty_req: session 0 alloc /dev/pts/42
debug1: server_input_channel_req: channel 0 request exec reply 1
debug1: session_by_channel: session 0 channel 0
debug1: session_input_channel_req: session 0 req exec
debug1: Values: options.num_allow_users: 0
debug1: RLOGIN VALUE :1
debug1: audit run command euid 0 user root command 'whoami'
setsid: Operation not permitted.
After setsid: Operation not permitted. it does nothing until I kill it with Ctrl+C. When I kill it it returns:
debug2: fd 4 setting TCP_NODELAY
debug3: packet_set_tos: set IP_TOS 0x10
debug2: channel 0: rfd 10 isatty
debug2: fd 10 setting O_NONBLOCK
debug3: fd 8 is O_NONBLOCK
debug2: notify_done: reading
Exiting on signal 2
debug1: do_cleanup
debug1: session_pty_cleanup: session 0 release /dev/pts/42
debug1: audit session close euid 0 user root tty name /dev/pts/42
debug1: audit event euid 0 user root event 12 (SSH_connabndn)
debug1: Return Val-1 for auditproc:0
And sends the result of whoami back to the client. This looks like a bug in SSH server, but is this possible for the 2 different versions?
Another interesting fact is when I run sshd with truss (kind of strace for AIX) the output looks like this:
debug1: session_input_channel_req: session 0 req pty-req
debug1: Allocating pty.
debug1: session_pty_req: session 0 alloc /dev/pts/42
debug1: server_input_channel_req: channel 0 request exec reply 1
debug1: session_by_channel: session 0 channel 0
debug1: session_input_channel_req: session 0 req exec
debug1: Values: options.num_allow_users: 0
debug1: RLOGIN VALUE :1
debug1: audit run command euid 0 user root command 'whoami'
debug2: fd 4 setting TCP_NODELAY
debug3: packet_set_tos: set IP_TOS 0x10
debug2: channel 0: rfd 10 isatty
debug2: fd 10 setting O_NONBLOCK
debug3: fd 8 is O_NONBLOCK
setsid: Operation not permitted.
debug2: channel 0: rcvd eof
debug2: channel 0: output open -> drain
debug2: channel 0: obuf empty
debug2: channel 0: close_write
debug2: channel 0: output drain -> closed
But truss output is a bit more strange than strace one (at least for someone who don't use *nix trace tools on daily basis) so I don't understand what is going on in the logs. If there is someone more skilled with this stuff here is the part of the trace data http://pastebin.com/YdzQwbt2 from debug1: RLOGIN VALUE :1.
Also, in the logs, I found that ssh.Shell() works because it doesn't request pty. It starts an interactive session (or something like that). But in my case, the interactive session is not an option.
better late than never
IBM said it was a bug in openssh - race condition while PTY allocation
https://www-01.ibm.com/support/docview.wss?uid=isg1IV82042
fixed in package openssh.base.server:7.5.102.1500
it strange that bug only occurs in aix, never in linux. nevertheless, problem is solved in my case
I had similar problem with "Allocating pty" and then exiting from ssh session. Here is log of my sshd debug:
sshd drops connection with error :3004-010 Failed setting terminal ownership and mode.
debug1: Allocating pty.
debug1: session_pty_req: session 0 alloc /dev/pts/2
debug1: Ignoring unsupported tty mode opcode 13 (0xd)
debug1: Ignoring unsupported tty mode opcode 18 (0x12)
debug1: server_input_channel_req: channel 0 request env reply 0
debug1: session_by_channel: session 0 channel 0
debug1: session_input_channel_req: session 0 req env
debug2: Ignoring env request LANG: disallowed name
debug1: server_input_channel_req: channel 0 request shell reply 1
debug1: session_by_channel: session 0 channel 0
debug1: session_input_channel_req: session 0 req shell
debug1: Values: options.num_allow_users: 0
debug1: RLOGIN VALUE :1
setsid: Operation not permitted.
The OS is AIX 7.1 (7100-04-03-1642)
The goal of my environment is to authenticate user on AIX through remote ldap user over ssh (ldap server actually is novell eDirectory).
So, I had similar issue with user authentication.
I fixed login over ssh as in eDirectory Schema (rfc2703), added following object extensions to the user:
posixAccount
posixGroup
shadowAccount
uamPosixUser (as I am not sure is it necessary this object)
I just want to note that on OS AIX following user isn't local, not exist in /etc/passwd and /etc/group.
V.Davidov